lucos_search_component 1.0.17 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5659,8 +5659,22 @@ class LucosSearchComponent extends HTMLSpanElement {
5659
5659
  shadow.appendChild(tomStyle);
5660
5660
  }
5661
5661
 
5662
+ const errorMessage = document.createElement('div');
5663
+ errorMessage.setAttribute('class', 'search-error');
5664
+ errorMessage.setAttribute('hidden', '');
5665
+ shadow.appendChild(errorMessage);
5666
+
5662
5667
  const mainStyle = document.createElement('style');
5663
5668
  mainStyle.textContent = `
5669
+ .search-error {
5670
+ color: #a00;
5671
+ font-size: 0.85em;
5672
+ margin-top: 4px;
5673
+ padding: 4px 6px;
5674
+ border: 1px solid #e0a0a0;
5675
+ background: #fff5f5;
5676
+ border-radius: 3px;
5677
+ }
5664
5678
  .lozenge {
5665
5679
  align-items: center;
5666
5680
  vertical-align: baseline;
@@ -5786,6 +5800,7 @@ class LucosSearchComponent extends HTMLSpanElement {
5786
5800
  closeAfterSelect: true,
5787
5801
  highlight: false, // Will use typesense's hightlight (as it can consider other fields)
5788
5802
  load: async function(query, callback) {
5803
+ errorMessage.setAttribute('hidden', '');
5789
5804
  const queryParams = new URLSearchParams({
5790
5805
  q: query,
5791
5806
  });
@@ -5794,9 +5809,15 @@ class LucosSearchComponent extends HTMLSpanElement {
5794
5809
  } else if (component.getAttribute("data-exclude_types")) {
5795
5810
  queryParams.set("filter_by",`type:![${component.getAttribute("data-exclude_types")}]`);
5796
5811
  }
5797
- const results = await component.searchRequest(queryParams);
5798
- this.clearOptions();
5799
- callback(results);
5812
+ try {
5813
+ const results = await component.searchRequest(queryParams);
5814
+ this.clearOptions();
5815
+ callback(results);
5816
+ } catch(err) {
5817
+ callback([]);
5818
+ errorMessage.textContent = err.userMessage || 'Search is currently unavailable — please try again later.';
5819
+ errorMessage.removeAttribute('hidden');
5820
+ }
5800
5821
  },
5801
5822
  plugins: {
5802
5823
  remove_button:{
@@ -5864,13 +5885,29 @@ class LucosSearchComponent extends HTMLSpanElement {
5864
5885
  searchParams.set('enable_highlight_v1', false);
5865
5886
  searchParams.set('highlight_start_tag', '<span class="highlight">');
5866
5887
  searchParams.set('highlight_end_tag', '</span>');
5867
- const response = await fetch("https://arachne.l42.eu/search?"+searchParams.toString(), {
5868
- headers: { 'X-TYPESENSE-API-KEY': key },
5869
- signal: AbortSignal.timeout(2000),
5870
- });
5888
+ let response;
5889
+ try {
5890
+ response = await fetch("https://arachne.l42.eu/search?"+searchParams.toString(), {
5891
+ headers: { 'X-TYPESENSE-API-KEY': key },
5892
+ signal: AbortSignal.timeout(8000),
5893
+ });
5894
+ } catch(err) {
5895
+ const userMessage = err.name === 'TimeoutError'
5896
+ ? 'Search timed out — please try again later.'
5897
+ : 'Search is currently unavailable — please try again later.';
5898
+ const error = new Error(`Search request failed: ${err.message}`);
5899
+ error.userMessage = userMessage;
5900
+ throw error;
5901
+ }
5871
5902
  const data = await response.json();
5872
5903
  if (!response.ok) {
5873
- throw new Error(`Recieved ${response.status} error from search endpoint: ${data["message"]}`);
5904
+ const error = new Error(`Received ${response.status} error from search endpoint: ${data["message"]}`);
5905
+ if (response.status === 502 || response.status === 503) {
5906
+ error.userMessage = 'Search backend is currently unavailable — please try again later.';
5907
+ } else {
5908
+ error.userMessage = 'Search encountered an error — please try again later.';
5909
+ }
5910
+ throw error;
5874
5911
  }
5875
5912
  const results = data.hits.map(result => {
5876
5913
  return {...result, ...result.document}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lucos_search_component",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "Web Components for searching lucOS data",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,8 +16,22 @@ class LucosSearchComponent extends HTMLSpanElement {
16
16
  shadow.appendChild(tomStyle);
17
17
  }
18
18
 
19
+ const errorMessage = document.createElement('div');
20
+ errorMessage.setAttribute('class', 'search-error');
21
+ errorMessage.setAttribute('hidden', '');
22
+ shadow.appendChild(errorMessage);
23
+
19
24
  const mainStyle = document.createElement('style');
20
25
  mainStyle.textContent = `
26
+ .search-error {
27
+ color: #a00;
28
+ font-size: 0.85em;
29
+ margin-top: 4px;
30
+ padding: 4px 6px;
31
+ border: 1px solid #e0a0a0;
32
+ background: #fff5f5;
33
+ border-radius: 3px;
34
+ }
21
35
  .lozenge {
22
36
  align-items: center;
23
37
  vertical-align: baseline;
@@ -143,6 +157,7 @@ class LucosSearchComponent extends HTMLSpanElement {
143
157
  closeAfterSelect: true,
144
158
  highlight: false, // Will use typesense's hightlight (as it can consider other fields)
145
159
  load: async function(query, callback) {
160
+ errorMessage.setAttribute('hidden', '');
146
161
  const queryParams = new URLSearchParams({
147
162
  q: query,
148
163
  });
@@ -151,9 +166,15 @@ class LucosSearchComponent extends HTMLSpanElement {
151
166
  } else if (component.getAttribute("data-exclude_types")) {
152
167
  queryParams.set("filter_by",`type:![${component.getAttribute("data-exclude_types")}]`);
153
168
  }
154
- const results = await component.searchRequest(queryParams);
155
- this.clearOptions();
156
- callback(results);
169
+ try {
170
+ const results = await component.searchRequest(queryParams);
171
+ this.clearOptions();
172
+ callback(results);
173
+ } catch(err) {
174
+ callback([]);
175
+ errorMessage.textContent = err.userMessage || 'Search is currently unavailable — please try again later.';
176
+ errorMessage.removeAttribute('hidden');
177
+ }
157
178
  },
158
179
  plugins: {
159
180
  remove_button:{
@@ -221,13 +242,29 @@ class LucosSearchComponent extends HTMLSpanElement {
221
242
  searchParams.set('enable_highlight_v1', false);
222
243
  searchParams.set('highlight_start_tag', '<span class="highlight">')
223
244
  searchParams.set('highlight_end_tag', '</span>');
224
- const response = await fetch("https://arachne.l42.eu/search?"+searchParams.toString(), {
225
- headers: { 'X-TYPESENSE-API-KEY': key },
226
- signal: AbortSignal.timeout(2000),
227
- });
245
+ let response;
246
+ try {
247
+ response = await fetch("https://arachne.l42.eu/search?"+searchParams.toString(), {
248
+ headers: { 'X-TYPESENSE-API-KEY': key },
249
+ signal: AbortSignal.timeout(8000),
250
+ });
251
+ } catch(err) {
252
+ const userMessage = err.name === 'TimeoutError'
253
+ ? 'Search timed out — please try again later.'
254
+ : 'Search is currently unavailable — please try again later.';
255
+ const error = new Error(`Search request failed: ${err.message}`);
256
+ error.userMessage = userMessage;
257
+ throw error;
258
+ }
228
259
  const data = await response.json();
229
260
  if (!response.ok) {
230
- throw new Error(`Recieved ${response.status} error from search endpoint: ${data["message"]}`);
261
+ const error = new Error(`Received ${response.status} error from search endpoint: ${data["message"]}`);
262
+ if (response.status === 502 || response.status === 503) {
263
+ error.userMessage = 'Search backend is currently unavailable — please try again later.';
264
+ } else {
265
+ error.userMessage = 'Search encountered an error — please try again later.';
266
+ }
267
+ throw error;
231
268
  }
232
269
  const results = data.hits.map(result => {
233
270
  return {...result, ...result.document}