@cloudflare/ai-search-snippet 0.0.27 → 0.0.28

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/main.d.ts CHANGED
@@ -218,6 +218,7 @@ declare class SearchBarSnippet extends HTMLElement {
218
218
  private showEmptyState;
219
219
  private showNoResultsState;
220
220
  private showErrorState;
221
+ private showMissingApiUrlError;
221
222
  private updateTheme;
222
223
  private cleanup;
223
224
  search(query: string): Promise<void>;
@@ -279,6 +280,7 @@ export declare class SearchModalSnippet extends HTMLElement {
279
280
  private clearLoadingInterval;
280
281
  private showNoResultsState;
281
282
  private showErrorState;
283
+ private showMissingApiUrlError;
282
284
  private updateTheme;
283
285
  private lockBodyScroll;
284
286
  private unlockBodyScroll;
@@ -13,7 +13,7 @@ const p = [
13
13
  "Rummaging through pages...",
14
14
  "Hunting down answers..."
15
15
  ];
16
- function $(o, i) {
16
+ function A(o, i) {
17
17
  let e;
18
18
  return function(...s) {
19
19
  const r = () => {
@@ -29,7 +29,7 @@ function h(o) {
29
29
  function S(o) {
30
30
  return new DOMParser().parseFromString(o, "text/html").documentElement.textContent || "";
31
31
  }
32
- function D(o) {
32
+ function P(o) {
33
33
  const i = new Date(o), t = (/* @__PURE__ */ new Date()).getTime() - i.getTime();
34
34
  if (t < 6e4)
35
35
  return "Just now";
@@ -48,7 +48,7 @@ function D(o) {
48
48
  minute: "2-digit"
49
49
  });
50
50
  }
51
- function A(o) {
51
+ function $(o) {
52
52
  return new Date(o).toLocaleDateString(void 0, {
53
53
  month: "short",
54
54
  day: "numeric"
@@ -79,9 +79,9 @@ function m(o, i) {
79
79
  function w(o) {
80
80
  if (!o)
81
81
  throw new Error("API URL is required");
82
- return new _(o);
82
+ return new D(o);
83
83
  }
84
- class _ {
84
+ class D {
85
85
  constructor(i) {
86
86
  a(this, "activeRequests", /* @__PURE__ */ new Map());
87
87
  a(this, "baseUrl");
@@ -235,10 +235,10 @@ class _ {
235
235
  return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
236
236
  }
237
237
  }
238
- const P = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w3.org/2000/svg" aria-label="Cloudflare" role="img">
238
+ const _ = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w3.org/2000/svg" aria-label="Cloudflare" role="img">
239
239
  <path fill="#f38020" d="m280.8395,183.31456c11,-26 -4,-38 -19,-38l-148,-2c-4,0 -4,-6 1,-7l150,-2c17,-1 37,-15 43,-33c0,0 10,-21 9,-24a97,97 0 0 0 -187,-11c-38,-25 -78,9 -69,46c-48,3 -65,46 -60,72c0,1 1,2 3,2l274,0c1,0 3,-1 3,-3z"/>
240
240
  <path fill="#faae40" d="m330.8395,81.31456c-4,0 -6,-1 -7,1l-5,21c-5,16 3,30 20,31l32,2c4,0 4,6 -1,7l-33,1c-36,4 -46,39 -46,39c0,2 0,3 2,3l113,0l3,-2a81,81 0 0 0 -78,-103"/>
241
- </svg>`, V = "https://workers.cloudflare.com/product/ai-search", x = `Powered by <a href="${V}" target="_blank" rel="noopener noreferrer">Cloudflare AI Search ${P}</a>`, B = `
241
+ </svg>`, U = "https://workers.cloudflare.com/product/ai-search", y = `Powered by <a href="${U}" target="_blank" rel="noopener noreferrer">Cloudflare AI Search ${_}</a>`, q = `
242
242
  /* Chat container */
243
243
  .chat-container {
244
244
  display: flex;
@@ -555,7 +555,7 @@ const P = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w
555
555
  .chat-message-bubble a:hover {
556
556
  text-decoration: none;
557
557
  }
558
- `, y = `
558
+ `, x = `
559
559
  :host {
560
560
  /* Colors - Light Mode */
561
561
  --search-snippet-primary-color: #2563eb;
@@ -990,9 +990,9 @@ const P = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w
990
990
  text-align: center;
991
991
  }
992
992
  `;
993
- function j(o) {
993
+ function V(o) {
994
994
  let i = o;
995
- i = O(i), i = i.replace(/```([\s\S]*?)```/g, (n, c) => `<pre><code>${c.trim()}</code></pre>`);
995
+ i = j(i), i = i.replace(/```([\s\S]*?)```/g, (n, c) => `<pre><code>${c.trim()}</code></pre>`);
996
996
  const e = i.split(`
997
997
  `), t = [];
998
998
  let s = !1, r = "";
@@ -1038,7 +1038,7 @@ function v(o) {
1038
1038
  '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
1039
1039
  ), i;
1040
1040
  }
1041
- function O(o) {
1041
+ function j(o) {
1042
1042
  const i = {
1043
1043
  "&": "&amp;",
1044
1044
  "<": "&lt;",
@@ -1048,7 +1048,7 @@ function O(o) {
1048
1048
  };
1049
1049
  return o.replace(/[&<>"']/g, (e) => i[e] || e);
1050
1050
  }
1051
- class q {
1051
+ class B {
1052
1052
  constructor(i, e, t) {
1053
1053
  a(this, "container");
1054
1054
  a(this, "client");
@@ -1219,11 +1219,11 @@ class q {
1219
1219
  <div class="chat-message-avatar">${s}</div>
1220
1220
  <div class="chat-message-content">
1221
1221
  <div class="chat-message-bubble">
1222
- ${i.content ? `<div class="chat-message-text">${j(i.content)}</div>` : ""}
1222
+ ${i.content ? `<div class="chat-message-text">${V(i.content)}</div>` : ""}
1223
1223
  ${e ? `<div class="chat-streaming"><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="loading-text">${p[this.loadingMessageIndex]}</span></div>` : ""}
1224
1224
  </div>
1225
1225
  <div class="chat-message-metadata">
1226
- <span class="chat-message-time">${D(i.timestamp)}</span>
1226
+ <span class="chat-message-time">${P(i.timestamp)}</span>
1227
1227
  </div>
1228
1228
  </div>
1229
1229
  </div>
@@ -1277,7 +1277,7 @@ class q {
1277
1277
  }
1278
1278
  }
1279
1279
  const E = "chat-bubble-snippet";
1280
- class K extends HTMLElement {
1280
+ class O extends HTMLElement {
1281
1281
  constructor() {
1282
1282
  super();
1283
1283
  a(this, "shadow");
@@ -1307,7 +1307,7 @@ class K extends HTMLElement {
1307
1307
  }
1308
1308
  getProps() {
1309
1309
  return {
1310
- apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
1310
+ apiUrl: d(this.getAttribute("api-url"), ""),
1311
1311
  placeholder: d(this.getAttribute("placeholder"), "Type a message..."),
1312
1312
  theme: d(this.getAttribute("theme"), "auto"),
1313
1313
  hideBranding: g(this.getAttribute("hide-branding"), !1)
@@ -1316,7 +1316,7 @@ class K extends HTMLElement {
1316
1316
  initializeClient() {
1317
1317
  const e = this.getProps();
1318
1318
  if (!e.apiUrl) {
1319
- console.error("ChatBubbleSnippet: api-url attribute is required");
1319
+ console.error("ChatBubbleSnippet: api-url attribute is required"), this.client = null;
1320
1320
  return;
1321
1321
  }
1322
1322
  try {
@@ -1327,8 +1327,8 @@ class K extends HTMLElement {
1327
1327
  }
1328
1328
  render() {
1329
1329
  const e = document.createElement("style");
1330
- e.textContent = `${y}
1331
- ${B}
1330
+ e.textContent = `${x}
1331
+ ${q}
1332
1332
  ${this.getBubbleStyles()}`, this.container = document.createElement("div"), this.container.className = "chat-bubble-widget", this.container.innerHTML = this.getBaseHTML(), this.shadow.innerHTML = "", this.shadow.appendChild(e), this.shadow.appendChild(this.container), this.attachEventListeners();
1333
1333
  }
1334
1334
  getBubbleStyles() {
@@ -1508,7 +1508,7 @@ ${this.getBubbleStyles()}`, this.container = document.createElement("div"), this
1508
1508
  </div>
1509
1509
  </div>
1510
1510
  <div class="chat-content"></div>
1511
- ${this.getProps().hideBranding ? "" : `<div class="powered-by">${x}</div>`}
1511
+ ${this.getProps().hideBranding ? "" : `<div class="powered-by">${y}</div>`}
1512
1512
  </div>
1513
1513
  `;
1514
1514
  }
@@ -1536,11 +1536,19 @@ ${this.getBubbleStyles()}`, this.container = document.createElement("div"), this
1536
1536
  this.isMinimized ? e?.classList.add("minimized") : e?.classList.remove("minimized");
1537
1537
  }
1538
1538
  initializeChatView() {
1539
- if (this.chatView || !this.client) return;
1539
+ if (this.chatView) return;
1540
1540
  const e = this.shadow.querySelector(".chat-content");
1541
1541
  if (!e) return;
1542
+ if (!this.client) {
1543
+ e.innerHTML = `
1544
+ <div style="padding: 16px; color: var(--search-snippet-error-color, #ef4444); font-family: var(--search-snippet-font-family, sans-serif); font-size: var(--search-snippet-font-size-base, 14px);">
1545
+ <strong>Error:</strong> The <code>api-url</code> attribute is required. Please provide a valid API URL.
1546
+ </div>
1547
+ `;
1548
+ return;
1549
+ }
1542
1550
  const t = this.getProps();
1543
- this.chatView = new q(e, this.client, t);
1551
+ this.chatView = new B(e, this.client, t);
1544
1552
  }
1545
1553
  updateTheme(e) {
1546
1554
  (e === "light" || e === "dark" ? e : null) === null && this.hasAttribute("theme") && this.getAttribute("theme") !== "auto" && this.removeAttribute("theme");
@@ -1559,9 +1567,9 @@ ${this.getBubbleStyles()}`, this.container = document.createElement("div"), this
1559
1567
  return this.chatView?.getMessages() || [];
1560
1568
  }
1561
1569
  }
1562
- customElements.get(E) || customElements.define(E, K);
1570
+ customElements.get(E) || customElements.define(E, O);
1563
1571
  const L = "chat-page-snippet", I = "chat-page-sessions";
1564
- class U extends HTMLElement {
1572
+ class K extends HTMLElement {
1565
1573
  constructor() {
1566
1574
  super();
1567
1575
  a(this, "shadow");
@@ -1593,7 +1601,7 @@ class U extends HTMLElement {
1593
1601
  }
1594
1602
  getProps() {
1595
1603
  return {
1596
- apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
1604
+ apiUrl: d(this.getAttribute("api-url"), ""),
1597
1605
  placeholder: d(this.getAttribute("placeholder"), "Type a message..."),
1598
1606
  theme: d(this.getAttribute("theme"), "auto"),
1599
1607
  hideBranding: g(this.getAttribute("hide-branding"), !1)
@@ -1602,7 +1610,7 @@ class U extends HTMLElement {
1602
1610
  initializeClient() {
1603
1611
  const e = this.getProps();
1604
1612
  if (!e.apiUrl) {
1605
- console.error("ChatPageSnippet: api-url attribute is required");
1613
+ console.error("ChatPageSnippet: api-url attribute is required"), this.client = null;
1606
1614
  return;
1607
1615
  }
1608
1616
  try {
@@ -1613,8 +1621,8 @@ class U extends HTMLElement {
1613
1621
  }
1614
1622
  render() {
1615
1623
  const e = document.createElement("style");
1616
- e.textContent = `${y}
1617
- ${B}
1624
+ e.textContent = `${x}
1625
+ ${q}
1618
1626
  ${this.getPageStyles()}`, this.container = document.createElement("div"), this.container.className = "chat-page-container", this.container.innerHTML = this.getBaseHTML(), this.shadow.innerHTML = "", this.shadow.appendChild(e), this.shadow.appendChild(this.container), this.attachEventListeners();
1619
1627
  }
1620
1628
  getPageStyles() {
@@ -1906,7 +1914,7 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
1906
1914
  New Chat
1907
1915
  </button>
1908
1916
  <div class="chat-list"></div>
1909
- ${this.getProps().hideBranding ? "" : `<div class="powered-by">${x}</div>`}
1917
+ ${this.getProps().hideBranding ? "" : `<div class="powered-by">${y}</div>`}
1910
1918
  </div>
1911
1919
  <div class="chat-main">
1912
1920
  <div class="chat-page-header">
@@ -1947,11 +1955,18 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
1947
1955
  this.handleClearClick && e?.removeEventListener("click", this.handleClearClick), this.handleNewChatClick && t?.removeEventListener("click", this.handleNewChatClick), this.handleToggleSidebarClick && s?.removeEventListener("click", this.handleToggleSidebarClick), this.handleChatListClick && r?.removeEventListener("click", this.handleChatListClick), this.handleMessageEvent && n && n.removeEventListener("message", this.handleMessageEvent), this.handleClearClick = null, this.handleNewChatClick = null, this.handleToggleSidebarClick = null, this.handleChatListClick = null, this.handleMessageEvent = null;
1948
1956
  }
1949
1957
  setupView() {
1950
- if (!this.client) return;
1951
1958
  const e = this.shadow.querySelector(".container");
1959
+ if (!this.client) {
1960
+ e && (e.innerHTML = `
1961
+ <div style="padding: 16px; color: var(--search-snippet-error-color, #ef4444); font-family: var(--search-snippet-font-family, sans-serif); font-size: var(--search-snippet-font-size-base, 14px);">
1962
+ <strong>Error:</strong> The <code>api-url</code> attribute is required. Please provide a valid API URL.
1963
+ </div>
1964
+ `);
1965
+ return;
1966
+ }
1952
1967
  if (!e) return;
1953
1968
  const t = this.getProps();
1954
- if (this.chatView = new q(e, this.client, t), this.sessions.length === 0)
1969
+ if (this.chatView = new B(e, this.client, t), this.sessions.length === 0)
1955
1970
  this.createNewChat();
1956
1971
  else {
1957
1972
  const s = this.sessions[0];
@@ -2092,7 +2107,7 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
2092
2107
  return this.sessions.find((e) => e.id === this.currentSessionId) || null;
2093
2108
  }
2094
2109
  }
2095
- customElements.get(L) || customElements.define(L, U);
2110
+ customElements.get(L) || customElements.define(L, K);
2096
2111
  const G = `
2097
2112
  /* Search view states */
2098
2113
  .search-view {
@@ -2509,7 +2524,7 @@ class F extends HTMLElement {
2509
2524
  }
2510
2525
  getProps() {
2511
2526
  return {
2512
- apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
2527
+ apiUrl: d(this.getAttribute("api-url"), ""),
2513
2528
  placeholder: d(this.getAttribute("placeholder"), "Search..."),
2514
2529
  maxResults: f(this.getAttribute("max-results"), 10),
2515
2530
  debounceMs: f(this.getAttribute("debounce-ms"), 300),
@@ -2524,7 +2539,7 @@ class F extends HTMLElement {
2524
2539
  initializeClient() {
2525
2540
  const e = this.getProps();
2526
2541
  if (!e.apiUrl) {
2527
- console.error("SearchBarSnippet: api-url attribute is required");
2542
+ console.error("SearchBarSnippet: api-url attribute is required"), this.client = null, this.showMissingApiUrlError();
2528
2543
  return;
2529
2544
  }
2530
2545
  try {
@@ -2535,12 +2550,12 @@ class F extends HTMLElement {
2535
2550
  }
2536
2551
  render() {
2537
2552
  const e = this.getProps(), t = (r) => this.performSearch(r);
2538
- this.debouncedSearch = $(
2553
+ this.debouncedSearch = A(
2539
2554
  t,
2540
2555
  e.debounceMs || 400
2541
2556
  );
2542
2557
  const s = document.createElement("style");
2543
- s.textContent = `${y}
2558
+ s.textContent = `${x}
2544
2559
  ${G}`, this.container = document.createElement("div"), this.container.className = "container", this.container.innerHTML = `
2545
2560
  <div class="search-view">
2546
2561
  <div class="search-input-wrapper">
@@ -2563,7 +2578,7 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2563
2578
  </div>
2564
2579
  </div>
2565
2580
  </div>
2566
- `, this.shadow.innerHTML = "", this.shadow.appendChild(s), this.shadow.appendChild(this.container), this.inputElement = this.container.querySelector(".search-input"), this.resultsContainer = this.container.querySelector(".search-results-wrapper"), this.searchButton = this.container.querySelector(".search-submit-button"), this.attachEventListeners();
2581
+ `, this.shadow.innerHTML = "", this.shadow.appendChild(s), this.shadow.appendChild(this.container), this.inputElement = this.container.querySelector(".search-input"), this.resultsContainer = this.container.querySelector(".search-results-wrapper"), this.searchButton = this.container.querySelector(".search-submit-button"), this.attachEventListeners(), this.client || this.showMissingApiUrlError();
2567
2582
  }
2568
2583
  attachEventListeners() {
2569
2584
  this.inputElement && (this.handleInputChange = (e) => {
@@ -2582,21 +2597,23 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2582
2597
  }, this.searchButton.addEventListener("click", this.handleSearchButtonClick)));
2583
2598
  }
2584
2599
  async performSearch(e) {
2585
- if (this.client) {
2586
- this.currentSearchController && (this.currentSearchController.abort(), this.currentSearchController = null), this.currentSearchController = new AbortController(), this.showLoadingState();
2587
- try {
2588
- const t = await this.client.search(e, {
2589
- streaming: !1,
2590
- signal: this.currentSearchController.signal
2591
- });
2592
- this.displayResults(t, e);
2593
- } catch (t) {
2594
- if (t.name === "AbortError")
2595
- return;
2596
- this.showErrorState(t.message);
2597
- } finally {
2598
- this.currentSearchController = null;
2599
- }
2600
+ if (!this.client) {
2601
+ this.showMissingApiUrlError();
2602
+ return;
2603
+ }
2604
+ this.currentSearchController && (this.currentSearchController.abort(), this.currentSearchController = null), this.currentSearchController = new AbortController(), this.showLoadingState();
2605
+ try {
2606
+ const t = await this.client.search(e, {
2607
+ streaming: !1,
2608
+ signal: this.currentSearchController.signal
2609
+ });
2610
+ this.displayResults(t, e);
2611
+ } catch (t) {
2612
+ if (t.name === "AbortError")
2613
+ return;
2614
+ this.showErrorState(t.message);
2615
+ } finally {
2616
+ this.currentSearchController = null;
2600
2617
  }
2601
2618
  }
2602
2619
  displayResults(e, t) {
@@ -2605,7 +2622,7 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2605
2622
  this.showNoResultsState(t);
2606
2623
  return;
2607
2624
  }
2608
- const s = this.getProps(), r = s.hideBranding ? "" : `<div class="powered-by-inline">${x}</div>`, n = s.seeMore ? `<div class="search-footer">
2625
+ const s = this.getProps(), r = s.hideBranding ? "" : `<div class="powered-by-inline">${y}</div>`, n = s.seeMore ? `<div class="search-footer">
2609
2626
  <a href="${h(s.seeMore + encodeURIComponent(t))}" class="search-see-more">
2610
2627
  <span>See more results</span>
2611
2628
  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
@@ -2625,7 +2642,7 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2625
2642
  this.resultsContainer.innerHTML = c, this.attachResultHandlers();
2626
2643
  }
2627
2644
  renderResult(e) {
2628
- const t = this.getProps(), s = t.hideThumbnails ? "" : this.renderResultImage(e.image, e.title), r = e.url ? h(e.url) : "#", n = t.showDate && e.timestamp !== void 0 ? `<div class="search-result-date">${h(A(e.timestamp))}</div>` : "", c = t.showUrl && e.url || n ? `<div class="search-result-metadata">
2645
+ const t = this.getProps(), s = t.hideThumbnails ? "" : this.renderResultImage(e.image, e.title), r = e.url ? h(e.url) : "#", n = t.showDate && e.timestamp !== void 0 ? `<div class="search-result-date">${h($(e.timestamp))}</div>` : "", c = t.showUrl && e.url || n ? `<div class="search-result-metadata">
2629
2646
  ${t.showUrl && e.url ? `<span class="search-result-url">${h(e.url)}</span>` : '<span class="search-result-url search-result-url-empty"></span>'}
2630
2647
  ${n}
2631
2648
  </div>` : "";
@@ -2732,6 +2749,9 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2732
2749
  </div>
2733
2750
  `);
2734
2751
  }
2752
+ showMissingApiUrlError() {
2753
+ this.resultsContainer && this.showErrorState("The api-url attribute is required. Please provide a valid API URL.");
2754
+ }
2735
2755
  updateTheme(e) {
2736
2756
  const t = e === "light" || e === "dark" || e === "auto" ? e : "auto";
2737
2757
  t === "auto" ? this.removeAttribute("theme") : this.setAttribute("theme", t);
@@ -3237,7 +3257,7 @@ class W extends HTMLElement {
3237
3257
  }
3238
3258
  getProps() {
3239
3259
  return {
3240
- apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
3260
+ apiUrl: d(this.getAttribute("api-url"), ""),
3241
3261
  placeholder: d(this.getAttribute("placeholder"), "Search..."),
3242
3262
  maxResults: f(this.getAttribute("max-results"), 10),
3243
3263
  debounceMs: f(this.getAttribute("debounce-ms"), 300),
@@ -3254,7 +3274,7 @@ class W extends HTMLElement {
3254
3274
  initializeClient() {
3255
3275
  const e = this.getProps();
3256
3276
  if (!e.apiUrl) {
3257
- console.error("SearchModalSnippet: api-url attribute is required");
3277
+ console.error("SearchModalSnippet: api-url attribute is required"), this.client = null, this.showMissingApiUrlError();
3258
3278
  return;
3259
3279
  }
3260
3280
  try {
@@ -3265,14 +3285,14 @@ class W extends HTMLElement {
3265
3285
  }
3266
3286
  render() {
3267
3287
  const e = this.getProps(), t = (c) => this.performSearch(c);
3268
- this.debouncedSearch = $(
3288
+ this.debouncedSearch = A(
3269
3289
  t,
3270
3290
  e.debounceMs || 300
3271
3291
  );
3272
3292
  const s = document.createElement("style");
3273
- s.textContent = `${y}
3293
+ s.textContent = `${x}
3274
3294
  ${Y}`;
3275
- const r = e.hideBranding ? "" : `<div class="powered-by-inline">${x}</div>`, n = document.createElement("div");
3295
+ const r = e.hideBranding ? "" : `<div class="powered-by-inline">${y}</div>`, n = document.createElement("div");
3276
3296
  n.innerHTML = `
3277
3297
  <div class="modal-backdrop" role="presentation"></div>
3278
3298
  <div class="modal-container" role="dialog" aria-modal="true" aria-labelledby="modal-title">
@@ -3316,7 +3336,7 @@ ${Y}`;
3316
3336
  ${r}
3317
3337
  </div>
3318
3338
  </div>
3319
- `, this.shadow.innerHTML = "", this.shadow.appendChild(s), this.shadow.appendChild(n), this.backdrop = this.shadow.querySelector(".modal-backdrop"), this.modal = this.shadow.querySelector(".modal-container"), this.inputElement = this.shadow.querySelector(".modal-search-input"), this.resultsContainer = this.shadow.querySelector(".modal-results"), this.footerCount = this.shadow.querySelector(".modal-results-count"), this.attachEventListeners();
3339
+ `, this.shadow.innerHTML = "", this.shadow.appendChild(s), this.shadow.appendChild(n), this.backdrop = this.shadow.querySelector(".modal-backdrop"), this.modal = this.shadow.querySelector(".modal-container"), this.inputElement = this.shadow.querySelector(".modal-search-input"), this.resultsContainer = this.shadow.querySelector(".modal-results"), this.footerCount = this.shadow.querySelector(".modal-results-count"), this.attachEventListeners(), this.client || this.showMissingApiUrlError();
3320
3340
  }
3321
3341
  attachGlobalKeyboardShortcut() {
3322
3342
  const e = this.getProps(), t = e.shortcut?.toLowerCase() || "k";
@@ -3377,21 +3397,23 @@ ${Y}`;
3377
3397
  t && e.url && t.click(), this.close();
3378
3398
  }
3379
3399
  async performSearch(e) {
3380
- if (this.client) {
3381
- this.currentSearchController && (this.currentSearchController.abort(), this.currentSearchController = null), this.currentSearchController = new AbortController(), this.showLoadingState();
3382
- try {
3383
- const t = await this.client.search(e, {
3384
- streaming: !1,
3385
- signal: this.currentSearchController.signal
3386
- }), s = this.getProps();
3387
- this.results = t.slice(0, s.maxResults || 10), this.activeIndex = this.results.length > 0 ? 0 : -1, this.displayResults(this.results, e);
3388
- } catch (t) {
3389
- if (t.name === "AbortError")
3390
- return;
3391
- this.showErrorState(t.message);
3392
- } finally {
3393
- this.currentSearchController = null;
3394
- }
3400
+ if (!this.client) {
3401
+ this.showMissingApiUrlError();
3402
+ return;
3403
+ }
3404
+ this.currentSearchController && (this.currentSearchController.abort(), this.currentSearchController = null), this.currentSearchController = new AbortController(), this.showLoadingState();
3405
+ try {
3406
+ const t = await this.client.search(e, {
3407
+ streaming: !1,
3408
+ signal: this.currentSearchController.signal
3409
+ }), s = this.getProps();
3410
+ this.results = t.slice(0, s.maxResults || 10), this.activeIndex = this.results.length > 0 ? 0 : -1, this.displayResults(this.results, e);
3411
+ } catch (t) {
3412
+ if (t.name === "AbortError")
3413
+ return;
3414
+ this.showErrorState(t.message);
3415
+ } finally {
3416
+ this.currentSearchController = null;
3395
3417
  }
3396
3418
  }
3397
3419
  displayResults(e, t) {
@@ -3407,7 +3429,7 @@ ${Y}`;
3407
3429
  this.resultsContainer.innerHTML = r + n, this.footerCount && (this.footerCount.textContent = `${e.length} result${e.length === 1 ? "" : "s"}`), this.inputElement && this.inputElement.setAttribute("aria-expanded", "true"), this.attachResultHandlers(), this.updateActiveResult();
3408
3430
  }
3409
3431
  renderResult(e, t) {
3410
- const s = this.getProps(), r = s.hideThumbnails ? "" : this.renderResultImage(e.image, e.title), n = e.url ? h(e.url) : "#", c = s.showDate && e.timestamp !== void 0 ? `<div class="modal-result-date">${h(A(e.timestamp))}</div>` : "", l = s.showUrl && e.url || c ? `<div class="modal-result-metadata">
3432
+ const s = this.getProps(), r = s.hideThumbnails ? "" : this.renderResultImage(e.image, e.title), n = e.url ? h(e.url) : "#", c = s.showDate && e.timestamp !== void 0 ? `<div class="modal-result-date">${h($(e.timestamp))}</div>` : "", l = s.showUrl && e.url || c ? `<div class="modal-result-metadata">
3411
3433
  ${s.showUrl && e.url ? `<span class="modal-result-url">${h(e.url)}</span>` : '<span class="modal-result-url modal-result-url-empty"></span>'}
3412
3434
  ${c}
3413
3435
  </div>` : "";
@@ -3523,6 +3545,9 @@ ${Y}`;
3523
3545
  </div>
3524
3546
  `, this.footerCount && (this.footerCount.textContent = "Error"));
3525
3547
  }
3548
+ showMissingApiUrlError() {
3549
+ this.resultsContainer && this.showErrorState("The api-url attribute is required. Please provide a valid API URL.");
3550
+ }
3526
3551
  updateTheme(e) {
3527
3552
  const t = e === "light" || e === "dark" || e === "auto" ? e : "auto";
3528
3553
  t === "auto" ? this.removeAttribute("theme") : this.setAttribute("theme", t);
@@ -3588,9 +3613,9 @@ ${Y}`;
3588
3613
  }
3589
3614
  customElements.get(T) || customElements.define(T, W);
3590
3615
  export {
3591
- _ as AISearchClient,
3592
- K as ChatBubbleSnippet,
3593
- U as ChatPageSnippet,
3616
+ D as AISearchClient,
3617
+ O as ChatBubbleSnippet,
3618
+ K as ChatPageSnippet,
3594
3619
  F as SearchBarSnippet,
3595
3620
  W as SearchModalSnippet,
3596
3621
  F as default