@cloudflare/ai-search-snippet 0.0.26 → 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.
@@ -1,6 +1,6 @@
1
- var R = Object.defineProperty;
2
- var H = (o, i, e) => i in o ? R(o, i, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[i] = e;
3
- var a = (o, i, e) => H(o, typeof i != "symbol" ? i + "" : i, e);
1
+ var H = Object.defineProperty;
2
+ var N = (o, i, e) => i in o ? H(o, i, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[i] = e;
3
+ var a = (o, i, e) => N(o, typeof i != "symbol" ? i + "" : i, e);
4
4
  const p = [
5
5
  "Searching...",
6
6
  "Digging through results...",
@@ -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 N(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,13 +48,19 @@ function N(o) {
48
48
  minute: "2-digit"
49
49
  });
50
50
  }
51
- function E(o = "id") {
51
+ function $(o) {
52
+ return new Date(o).toLocaleDateString(void 0, {
53
+ month: "short",
54
+ day: "numeric"
55
+ });
56
+ }
57
+ function M(o = "id") {
52
58
  return `${o}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
53
59
  }
54
60
  function d(o, i) {
55
61
  return o !== null ? o : i;
56
62
  }
57
- function m(o, i) {
63
+ function g(o, i) {
58
64
  return o === null ? i : o === "true" || o === "";
59
65
  }
60
66
  function f(o, i) {
@@ -62,7 +68,7 @@ function f(o, i) {
62
68
  const e = Number.parseInt(o, 10);
63
69
  return Number.isNaN(e) ? i : e;
64
70
  }
65
- function g(o, i) {
71
+ function m(o, i) {
66
72
  return new CustomEvent(o, {
67
73
  detail: i,
68
74
  bubbles: !0,
@@ -73,31 +79,14 @@ function g(o, i) {
73
79
  function w(o) {
74
80
  if (!o)
75
81
  throw new Error("API URL is required");
76
- return new P(o);
82
+ return new D(o);
77
83
  }
78
- class _ {
84
+ class D {
79
85
  constructor(i) {
80
86
  a(this, "activeRequests", /* @__PURE__ */ new Map());
81
87
  a(this, "baseUrl");
82
88
  this.baseUrl = i.replace(/\/$/, "");
83
89
  }
84
- search(i, e) {
85
- throw new Error("Not implemented");
86
- }
87
- searchStream(i, e) {
88
- throw new Error("Not implemented");
89
- }
90
- chat(i, e) {
91
- throw new Error("Not implemented");
92
- }
93
- cancelRequest(i) {
94
- throw new Error("Not implemented");
95
- }
96
- cancelAllRequests() {
97
- throw new Error("Not implemented");
98
- }
99
- }
100
- class P extends _ {
101
90
  request(i = {}, e, t) {
102
91
  const s = e === "search" ? "snippet-search" : "snippet-chat-completions";
103
92
  return fetch(`${this.baseUrl}/${e}`, {
@@ -128,7 +117,7 @@ class P extends _ {
128
117
  {
129
118
  query: i,
130
119
  streaming: !1,
131
- maxResults: 30
120
+ maxResults: e.maxResults || 30
132
121
  },
133
122
  "search",
134
123
  r
@@ -145,6 +134,7 @@ class P extends _ {
145
134
  id: l.id,
146
135
  title: S(l.item.metadata?.title),
147
136
  description: l.item.metadata?.description ? S(l.item.metadata?.description) : "",
137
+ timestamp: l.item.timestamp ?? void 0,
148
138
  url: l.item.key,
149
139
  image: l.item.metadata?.image || void 0,
150
140
  metadata: l.item.metadata
@@ -176,8 +166,8 @@ class P extends _ {
176
166
  const { done: u, value: C } = await l.read();
177
167
  if (u)
178
168
  break;
179
- const B = b.decode(C, { stream: !0 });
180
- c += B;
169
+ const R = b.decode(C, { stream: !0 });
170
+ c += R;
181
171
  }
182
172
  yield {
183
173
  type: "result",
@@ -245,10 +235,10 @@ class P extends _ {
245
235
  return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
246
236
  }
247
237
  }
248
- const V = `<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">
249
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"/>
250
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"/>
251
- </svg>`, j = "https://search.ai.cloudflare.com", y = `Powered by <a href="${j}" target="_blank" rel="noopener noreferrer">Cloudflare AI Search ${V}</a>`, $ = `
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 = `
252
242
  /* Chat container */
253
243
  .chat-container {
254
244
  display: flex;
@@ -1000,9 +990,9 @@ const V = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w
1000
990
  text-align: center;
1001
991
  }
1002
992
  `;
1003
- function D(o) {
993
+ function V(o) {
1004
994
  let i = o;
1005
- 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>`);
1006
996
  const e = i.split(`
1007
997
  `), t = [];
1008
998
  let s = !1, r = "";
@@ -1048,7 +1038,7 @@ function v(o) {
1048
1038
  '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
1049
1039
  ), i;
1050
1040
  }
1051
- function O(o) {
1041
+ function j(o) {
1052
1042
  const i = {
1053
1043
  "&": "&amp;",
1054
1044
  "<": "&lt;",
@@ -1058,7 +1048,7 @@ function O(o) {
1058
1048
  };
1059
1049
  return o.replace(/[&<>"']/g, (e) => i[e] || e);
1060
1050
  }
1061
- class q {
1051
+ class B {
1062
1052
  constructor(i, e, t) {
1063
1053
  a(this, "container");
1064
1054
  a(this, "client");
@@ -1137,13 +1127,13 @@ class q {
1137
1127
  */
1138
1128
  async sendMessage(i) {
1139
1129
  const e = {
1140
- id: E("msg"),
1130
+ id: M("msg"),
1141
1131
  role: "user",
1142
1132
  content: i,
1143
1133
  timestamp: Date.now()
1144
1134
  };
1145
1135
  this.addMessage(e), this.renderMessages(!0), this.setStreamingState(!0);
1146
- const t = E("msg"), s = {
1136
+ const t = M("msg"), s = {
1147
1137
  id: t,
1148
1138
  role: "assistant",
1149
1139
  content: "",
@@ -1161,10 +1151,10 @@ class q {
1161
1151
  break;
1162
1152
  }
1163
1153
  const c = this.messages.findIndex((l) => l.id === t);
1164
- c !== -1 && (this.messages[c].content = n), this.container.dispatchEvent(g("message", { message: s }));
1154
+ c !== -1 && (this.messages[c].content = n), this.container.dispatchEvent(m("message", { message: s }));
1165
1155
  } catch (r) {
1166
1156
  this.showErrorInMessage(t, r.message), this.container.dispatchEvent(
1167
- g("error", {
1157
+ m("error", {
1168
1158
  error: {
1169
1159
  message: r.message,
1170
1160
  code: "CHAT_ERROR"
@@ -1229,11 +1219,11 @@ class q {
1229
1219
  <div class="chat-message-avatar">${s}</div>
1230
1220
  <div class="chat-message-content">
1231
1221
  <div class="chat-message-bubble">
1232
- ${i.content ? `<div class="chat-message-text">${D(i.content)}</div>` : ""}
1222
+ ${i.content ? `<div class="chat-message-text">${V(i.content)}</div>` : ""}
1233
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>` : ""}
1234
1224
  </div>
1235
1225
  <div class="chat-message-metadata">
1236
- <span class="chat-message-time">${N(i.timestamp)}</span>
1226
+ <span class="chat-message-time">${P(i.timestamp)}</span>
1237
1227
  </div>
1238
1228
  </div>
1239
1229
  </div>
@@ -1286,8 +1276,8 @@ class q {
1286
1276
  this.clearLoadingMessages(), this.isStreaming && this.client.cancelAllRequests(), this.inputElement && (this.handleInputResize && this.inputElement.removeEventListener("input", this.handleInputResize), this.handleInputKeydown && this.inputElement.removeEventListener("keydown", this.handleInputKeydown)), this.sendButton && this.handleSendClick && this.sendButton.removeEventListener("click", this.handleSendClick), this.handleInputResize = null, this.handleInputKeydown = null, this.handleSendClick = null;
1287
1277
  }
1288
1278
  }
1289
- const M = "chat-bubble-snippet";
1290
- class K extends HTMLElement {
1279
+ const E = "chat-bubble-snippet";
1280
+ class O extends HTMLElement {
1291
1281
  constructor() {
1292
1282
  super();
1293
1283
  a(this, "shadow");
@@ -1307,7 +1297,7 @@ class K extends HTMLElement {
1307
1297
  return ["api-url", "placeholder", "theme", "hide-branding"];
1308
1298
  }
1309
1299
  connectedCallback() {
1310
- this.render(), this.initializeClient(), this.dispatchEvent(g("ready", void 0));
1300
+ this.render(), this.initializeClient(), this.dispatchEvent(m("ready", void 0));
1311
1301
  }
1312
1302
  disconnectedCallback() {
1313
1303
  this.cleanup();
@@ -1317,16 +1307,16 @@ class K extends HTMLElement {
1317
1307
  }
1318
1308
  getProps() {
1319
1309
  return {
1320
- apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
1310
+ apiUrl: d(this.getAttribute("api-url"), ""),
1321
1311
  placeholder: d(this.getAttribute("placeholder"), "Type a message..."),
1322
1312
  theme: d(this.getAttribute("theme"), "auto"),
1323
- hideBranding: m(this.getAttribute("hide-branding"), !1)
1313
+ hideBranding: g(this.getAttribute("hide-branding"), !1)
1324
1314
  };
1325
1315
  }
1326
1316
  initializeClient() {
1327
1317
  const e = this.getProps();
1328
1318
  if (!e.apiUrl) {
1329
- console.error("ChatBubbleSnippet: api-url attribute is required");
1319
+ console.error("ChatBubbleSnippet: api-url attribute is required"), this.client = null;
1330
1320
  return;
1331
1321
  }
1332
1322
  try {
@@ -1338,7 +1328,7 @@ class K extends HTMLElement {
1338
1328
  render() {
1339
1329
  const e = document.createElement("style");
1340
1330
  e.textContent = `${x}
1341
- ${$}
1331
+ ${q}
1342
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();
1343
1333
  }
1344
1334
  getBubbleStyles() {
@@ -1546,11 +1536,19 @@ ${this.getBubbleStyles()}`, this.container = document.createElement("div"), this
1546
1536
  this.isMinimized ? e?.classList.add("minimized") : e?.classList.remove("minimized");
1547
1537
  }
1548
1538
  initializeChatView() {
1549
- if (this.chatView || !this.client) return;
1539
+ if (this.chatView) return;
1550
1540
  const e = this.shadow.querySelector(".chat-content");
1551
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
+ }
1552
1550
  const t = this.getProps();
1553
- this.chatView = new q(e, this.client, t);
1551
+ this.chatView = new B(e, this.client, t);
1554
1552
  }
1555
1553
  updateTheme(e) {
1556
1554
  (e === "light" || e === "dark" ? e : null) === null && this.hasAttribute("theme") && this.getAttribute("theme") !== "auto" && this.removeAttribute("theme");
@@ -1569,9 +1567,9 @@ ${this.getBubbleStyles()}`, this.container = document.createElement("div"), this
1569
1567
  return this.chatView?.getMessages() || [];
1570
1568
  }
1571
1569
  }
1572
- customElements.get(M) || customElements.define(M, K);
1570
+ customElements.get(E) || customElements.define(E, O);
1573
1571
  const L = "chat-page-snippet", I = "chat-page-sessions";
1574
- class U extends HTMLElement {
1572
+ class K extends HTMLElement {
1575
1573
  constructor() {
1576
1574
  super();
1577
1575
  a(this, "shadow");
@@ -1593,7 +1591,7 @@ class U extends HTMLElement {
1593
1591
  return ["api-url", "placeholder", "theme", "hide-branding"];
1594
1592
  }
1595
1593
  connectedCallback() {
1596
- this.render(), this.initializeClient(), this.setupView(), this.dispatchEvent(g("ready", void 0));
1594
+ this.render(), this.initializeClient(), this.setupView(), this.dispatchEvent(m("ready", void 0));
1597
1595
  }
1598
1596
  disconnectedCallback() {
1599
1597
  this.saveCurrentSession(), this.cleanup();
@@ -1603,16 +1601,16 @@ class U extends HTMLElement {
1603
1601
  }
1604
1602
  getProps() {
1605
1603
  return {
1606
- apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
1604
+ apiUrl: d(this.getAttribute("api-url"), ""),
1607
1605
  placeholder: d(this.getAttribute("placeholder"), "Type a message..."),
1608
1606
  theme: d(this.getAttribute("theme"), "auto"),
1609
- hideBranding: m(this.getAttribute("hide-branding"), !1)
1607
+ hideBranding: g(this.getAttribute("hide-branding"), !1)
1610
1608
  };
1611
1609
  }
1612
1610
  initializeClient() {
1613
1611
  const e = this.getProps();
1614
1612
  if (!e.apiUrl) {
1615
- console.error("ChatPageSnippet: api-url attribute is required");
1613
+ console.error("ChatPageSnippet: api-url attribute is required"), this.client = null;
1616
1614
  return;
1617
1615
  }
1618
1616
  try {
@@ -1624,7 +1622,7 @@ class U extends HTMLElement {
1624
1622
  render() {
1625
1623
  const e = document.createElement("style");
1626
1624
  e.textContent = `${x}
1627
- ${$}
1625
+ ${q}
1628
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();
1629
1627
  }
1630
1628
  getPageStyles() {
@@ -1957,11 +1955,18 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
1957
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;
1958
1956
  }
1959
1957
  setupView() {
1960
- if (!this.client) return;
1961
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
+ }
1962
1967
  if (!e) return;
1963
1968
  const t = this.getProps();
1964
- 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)
1965
1970
  this.createNewChat();
1966
1971
  else {
1967
1972
  const s = this.sessions[0];
@@ -2102,7 +2107,7 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
2102
2107
  return this.sessions.find((e) => e.id === this.currentSessionId) || null;
2103
2108
  }
2104
2109
  }
2105
- customElements.get(L) || customElements.define(L, U);
2110
+ customElements.get(L) || customElements.define(L, K);
2106
2111
  const G = `
2107
2112
  /* Search view states */
2108
2113
  .search-view {
@@ -2349,12 +2354,36 @@ a.search-result-item:focus-visible {
2349
2354
  overflow: hidden;
2350
2355
  }
2351
2356
 
2357
+ .search-result-metadata {
2358
+ display: flex;
2359
+ align-items: center;
2360
+ gap: var(--search-snippet-spacing-sm);
2361
+ margin-top: var(--search-snippet-spacing-xs);
2362
+ min-width: 0;
2363
+ }
2364
+
2352
2365
  .search-result-url {
2353
2366
  font-size: var(--search-snippet-font-size-sm);
2354
2367
  color: var(--search-snippet-primary-color);
2355
- margin-top: var(--search-snippet-spacing-xs);
2356
2368
  text-decoration: none;
2357
- display: inline-block;
2369
+ display: block;
2370
+ flex: 1;
2371
+ min-width: 0;
2372
+ overflow: hidden;
2373
+ text-overflow: ellipsis;
2374
+ white-space: nowrap;
2375
+ }
2376
+
2377
+ .search-result-url-empty {
2378
+ visibility: hidden;
2379
+ }
2380
+
2381
+ .search-result-date {
2382
+ font-size: 12px;
2383
+ font-weight: var(--search-snippet-font-weight-medium);
2384
+ color: var(--search-snippet-text-secondary);
2385
+ text-align: right;
2386
+ flex-shrink: 0;
2358
2387
  }
2359
2388
 
2360
2389
  .search-result-url:hover {
@@ -2479,12 +2508,13 @@ class F extends HTMLElement {
2479
2508
  "theme",
2480
2509
  "hide-branding",
2481
2510
  "show-url",
2511
+ "show-date",
2482
2512
  "hide-thumbnails",
2483
2513
  "see-more"
2484
2514
  ];
2485
2515
  }
2486
2516
  connectedCallback() {
2487
- this.initializeClient(), this.render(), this.dispatchEvent(g("ready", void 0));
2517
+ this.initializeClient(), this.render(), this.dispatchEvent(m("ready", void 0));
2488
2518
  }
2489
2519
  disconnectedCallback() {
2490
2520
  this.cleanup();
@@ -2494,21 +2524,22 @@ class F extends HTMLElement {
2494
2524
  }
2495
2525
  getProps() {
2496
2526
  return {
2497
- apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
2527
+ apiUrl: d(this.getAttribute("api-url"), ""),
2498
2528
  placeholder: d(this.getAttribute("placeholder"), "Search..."),
2499
2529
  maxResults: f(this.getAttribute("max-results"), 10),
2500
2530
  debounceMs: f(this.getAttribute("debounce-ms"), 300),
2501
2531
  theme: d(this.getAttribute("theme"), "auto"),
2502
- hideBranding: m(this.getAttribute("hide-branding"), !1),
2503
- showUrl: m(this.getAttribute("show-url"), !1),
2504
- hideThumbnails: m(this.getAttribute("hide-thumbnails"), !1),
2532
+ hideBranding: g(this.getAttribute("hide-branding"), !1),
2533
+ showUrl: g(this.getAttribute("show-url"), !1),
2534
+ showDate: g(this.getAttribute("show-date"), !1),
2535
+ hideThumbnails: g(this.getAttribute("hide-thumbnails"), !1),
2505
2536
  seeMore: d(this.getAttribute("see-more"), "")
2506
2537
  };
2507
2538
  }
2508
2539
  initializeClient() {
2509
2540
  const e = this.getProps();
2510
2541
  if (!e.apiUrl) {
2511
- console.error("SearchBarSnippet: api-url attribute is required");
2542
+ console.error("SearchBarSnippet: api-url attribute is required"), this.client = null, this.showMissingApiUrlError();
2512
2543
  return;
2513
2544
  }
2514
2545
  try {
@@ -2547,7 +2578,7 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2547
2578
  </div>
2548
2579
  </div>
2549
2580
  </div>
2550
- `, 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();
2551
2582
  }
2552
2583
  attachEventListeners() {
2553
2584
  this.inputElement && (this.handleInputChange = (e) => {
@@ -2566,21 +2597,23 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2566
2597
  }, this.searchButton.addEventListener("click", this.handleSearchButtonClick)));
2567
2598
  }
2568
2599
  async performSearch(e) {
2569
- if (this.client) {
2570
- this.currentSearchController && (this.currentSearchController.abort(), this.currentSearchController = null), this.currentSearchController = new AbortController(), this.showLoadingState();
2571
- try {
2572
- const t = await this.client.search(e, {
2573
- streaming: !1,
2574
- signal: this.currentSearchController.signal
2575
- });
2576
- this.displayResults(t, e);
2577
- } catch (t) {
2578
- if (t.name === "AbortError")
2579
- return;
2580
- this.showErrorState(t.message);
2581
- } finally {
2582
- this.currentSearchController = null;
2583
- }
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;
2584
2617
  }
2585
2618
  }
2586
2619
  displayResults(e, t) {
@@ -2609,14 +2642,17 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2609
2642
  this.resultsContainer.innerHTML = c, this.attachResultHandlers();
2610
2643
  }
2611
2644
  renderResult(e) {
2612
- const t = this.getProps(), s = t.hideThumbnails ? "" : this.renderResultImage(e.image, e.title);
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">
2646
+ ${t.showUrl && e.url ? `<span class="search-result-url">${h(e.url)}</span>` : '<span class="search-result-url search-result-url-empty"></span>'}
2647
+ ${n}
2648
+ </div>` : "";
2613
2649
  return `
2614
- <a href="${e.url ? h(e.url) : "#"}" class="search-result-item" data-result-id="${h(e.url || "")}">
2650
+ <a href="${r}" class="search-result-item" data-result-id="${h(e.url || "")}">
2615
2651
  ${s}
2616
2652
  <div class="search-result-content">
2617
2653
  <div class="search-result-title">${h(e.title || "")}</div>
2618
2654
  <div class="search-result-snippet">${h(e.description || "")}</div>
2619
- ${t.showUrl && e.url ? `<span class="search-result-url">${h(e.url)}</span>` : ""}
2655
+ ${c}
2620
2656
  </div>
2621
2657
  </a>
2622
2658
  `;
@@ -2713,6 +2749,9 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2713
2749
  </div>
2714
2750
  `);
2715
2751
  }
2752
+ showMissingApiUrlError() {
2753
+ this.resultsContainer && this.showErrorState("The api-url attribute is required. Please provide a valid API URL.");
2754
+ }
2716
2755
  updateTheme(e) {
2717
2756
  const t = e === "light" || e === "dark" || e === "auto" ? e : "auto";
2718
2757
  t === "auto" ? this.removeAttribute("theme") : this.setAttribute("theme", t);
@@ -2978,17 +3017,37 @@ a.modal-result-item:focus-visible {
2978
3017
  overflow: hidden;
2979
3018
  }
2980
3019
 
3020
+ .modal-result-metadata {
3021
+ display: flex;
3022
+ align-items: center;
3023
+ gap: var(--search-snippet-spacing-sm);
3024
+ min-width: 0;
3025
+ }
3026
+
2981
3027
  .modal-result-url {
2982
3028
  font-size: var(--search-snippet-font-size-sm);
2983
3029
  color: var(--search-snippet-primary-color);
2984
3030
  text-decoration: none;
2985
- display: inline-block;
2986
- max-width: 100%;
3031
+ display: block;
3032
+ flex: 1;
3033
+ min-width: 0;
2987
3034
  overflow: hidden;
2988
3035
  text-overflow: ellipsis;
2989
3036
  white-space: nowrap;
2990
3037
  }
2991
3038
 
3039
+ .modal-result-url-empty {
3040
+ visibility: hidden;
3041
+ }
3042
+
3043
+ .modal-result-date {
3044
+ font-size: 12px;
3045
+ font-weight: var(--search-snippet-font-weight-medium);
3046
+ color: var(--search-snippet-text-secondary);
3047
+ text-align: right;
3048
+ flex-shrink: 0;
3049
+ }
3050
+
2992
3051
  .modal-result-url:hover {
2993
3052
  text-decoration: underline;
2994
3053
  }
@@ -3182,12 +3241,13 @@ class W extends HTMLElement {
3182
3241
  "debounce-ms",
3183
3242
  "hide-branding",
3184
3243
  "show-url",
3244
+ "show-date",
3185
3245
  "hide-thumbnails",
3186
3246
  "see-more"
3187
3247
  ];
3188
3248
  }
3189
3249
  connectedCallback() {
3190
- this.initializeClient(), this.render(), this.attachGlobalKeyboardShortcut(), this.dispatchEvent(g("ready", void 0));
3250
+ this.initializeClient(), this.render(), this.attachGlobalKeyboardShortcut(), this.dispatchEvent(m("ready", void 0));
3191
3251
  }
3192
3252
  disconnectedCallback() {
3193
3253
  this.cleanup();
@@ -3197,23 +3257,24 @@ class W extends HTMLElement {
3197
3257
  }
3198
3258
  getProps() {
3199
3259
  return {
3200
- apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
3260
+ apiUrl: d(this.getAttribute("api-url"), ""),
3201
3261
  placeholder: d(this.getAttribute("placeholder"), "Search..."),
3202
3262
  maxResults: f(this.getAttribute("max-results"), 10),
3203
3263
  debounceMs: f(this.getAttribute("debounce-ms"), 300),
3204
3264
  theme: d(this.getAttribute("theme"), "auto"),
3205
3265
  shortcut: d(this.getAttribute("shortcut"), "k"),
3206
3266
  useMetaKey: this.getAttribute("use-meta-key") !== "false",
3207
- hideBranding: m(this.getAttribute("hide-branding"), !1),
3208
- showUrl: m(this.getAttribute("show-url"), !1),
3209
- hideThumbnails: m(this.getAttribute("hide-thumbnails"), !1),
3267
+ hideBranding: g(this.getAttribute("hide-branding"), !1),
3268
+ showUrl: g(this.getAttribute("show-url"), !1),
3269
+ showDate: g(this.getAttribute("show-date"), !1),
3270
+ hideThumbnails: g(this.getAttribute("hide-thumbnails"), !1),
3210
3271
  seeMore: d(this.getAttribute("see-more"), "")
3211
3272
  };
3212
3273
  }
3213
3274
  initializeClient() {
3214
3275
  const e = this.getProps();
3215
3276
  if (!e.apiUrl) {
3216
- console.error("SearchModalSnippet: api-url attribute is required");
3277
+ console.error("SearchModalSnippet: api-url attribute is required"), this.client = null, this.showMissingApiUrlError();
3217
3278
  return;
3218
3279
  }
3219
3280
  try {
@@ -3275,7 +3336,7 @@ ${Y}`;
3275
3336
  ${r}
3276
3337
  </div>
3277
3338
  </div>
3278
- `, 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();
3279
3340
  }
3280
3341
  attachGlobalKeyboardShortcut() {
3281
3342
  const e = this.getProps(), t = e.shortcut?.toLowerCase() || "k";
@@ -3325,7 +3386,7 @@ ${Y}`;
3325
3386
  }
3326
3387
  const e = this.results[this.activeIndex];
3327
3388
  this.dispatchEvent(
3328
- g("result-select", {
3389
+ m("result-select", {
3329
3390
  result: e,
3330
3391
  index: this.activeIndex
3331
3392
  })
@@ -3336,21 +3397,23 @@ ${Y}`;
3336
3397
  t && e.url && t.click(), this.close();
3337
3398
  }
3338
3399
  async performSearch(e) {
3339
- if (this.client) {
3340
- this.currentSearchController && (this.currentSearchController.abort(), this.currentSearchController = null), this.currentSearchController = new AbortController(), this.showLoadingState();
3341
- try {
3342
- const t = await this.client.search(e, {
3343
- streaming: !1,
3344
- signal: this.currentSearchController.signal
3345
- }), s = this.getProps();
3346
- this.results = t.slice(0, s.maxResults || 10), this.activeIndex = this.results.length > 0 ? 0 : -1, this.displayResults(this.results, e);
3347
- } catch (t) {
3348
- if (t.name === "AbortError")
3349
- return;
3350
- this.showErrorState(t.message);
3351
- } finally {
3352
- this.currentSearchController = null;
3353
- }
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;
3354
3417
  }
3355
3418
  }
3356
3419
  displayResults(e, t) {
@@ -3366,10 +3429,13 @@ ${Y}`;
3366
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();
3367
3430
  }
3368
3431
  renderResult(e, t) {
3369
- const s = this.getProps(), r = s.hideThumbnails ? "" : this.renderResultImage(e.image, e.title);
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">
3433
+ ${s.showUrl && e.url ? `<span class="modal-result-url">${h(e.url)}</span>` : '<span class="modal-result-url modal-result-url-empty"></span>'}
3434
+ ${c}
3435
+ </div>` : "";
3370
3436
  return `
3371
3437
  <a
3372
- href="${e.url ? h(e.url) : "#"}"
3438
+ href="${n}"
3373
3439
  class="modal-result-item${t === this.activeIndex ? " active" : ""}"
3374
3440
  role="option"
3375
3441
  id="result-${t}"
@@ -3382,7 +3448,7 @@ ${Y}`;
3382
3448
  <div class="modal-result-content">
3383
3449
  <div class="modal-result-title">${h(e.title || "")}</div>
3384
3450
  ${e.description ? `<div class="modal-result-description">${h(e.description)}</div>` : ""}
3385
- ${s.showUrl && e.url ? `<span class="modal-result-url">${h(e.url)}</span>` : ""}
3451
+ ${l}
3386
3452
  </div>
3387
3453
  </a>
3388
3454
  `;
@@ -3479,6 +3545,9 @@ ${Y}`;
3479
3545
  </div>
3480
3546
  `, this.footerCount && (this.footerCount.textContent = "Error"));
3481
3547
  }
3548
+ showMissingApiUrlError() {
3549
+ this.resultsContainer && this.showErrorState("The api-url attribute is required. Please provide a valid API URL.");
3550
+ }
3482
3551
  updateTheme(e) {
3483
3552
  const t = e === "light" || e === "dark" || e === "auto" ? e : "auto";
3484
3553
  t === "auto" ? this.removeAttribute("theme") : this.setAttribute("theme", t);
@@ -3509,13 +3578,13 @@ ${Y}`;
3509
3578
  requestAnimationFrame(() => {
3510
3579
  this.inputElement?.focus();
3511
3580
  });
3512
- }), this.lockBodyScroll(), this.dispatchEvent(g("open", void 0)));
3581
+ }), this.lockBodyScroll(), this.dispatchEvent(m("open", void 0)));
3513
3582
  }
3514
3583
  /**
3515
3584
  * Close the search modal
3516
3585
  */
3517
3586
  close() {
3518
- this.isOpen && (this.isOpen = !1, this.backdrop?.classList.remove("open"), this.modal?.classList.remove("open"), this.inputElement && (this.inputElement.value = ""), this.results = [], this.activeIndex = -1, this.showEmptyState(), this.unlockBodyScroll(), this.dispatchEvent(g("close", void 0)));
3587
+ this.isOpen && (this.isOpen = !1, this.backdrop?.classList.remove("open"), this.modal?.classList.remove("open"), this.inputElement && (this.inputElement.value = ""), this.results = [], this.activeIndex = -1, this.showEmptyState(), this.unlockBodyScroll(), this.dispatchEvent(m("close", void 0)));
3519
3588
  }
3520
3589
  /**
3521
3590
  * Toggle the search modal open/closed
@@ -3544,9 +3613,9 @@ ${Y}`;
3544
3613
  }
3545
3614
  customElements.get(T) || customElements.define(T, W);
3546
3615
  export {
3547
- P as AISearchClient,
3548
- K as ChatBubbleSnippet,
3549
- U as ChatPageSnippet,
3616
+ D as AISearchClient,
3617
+ O as ChatBubbleSnippet,
3618
+ K as ChatPageSnippet,
3550
3619
  F as SearchBarSnippet,
3551
3620
  W as SearchModalSnippet,
3552
3621
  F as default