@seekora-ai/ui-sdk-vanilla 0.2.14 → 0.2.16

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.esm.js CHANGED
@@ -348,7 +348,7 @@ class SearchBar {
348
348
  }
349
349
  this.container = container;
350
350
  this.options = {
351
- placeholder: options.placeholder || 'Search...',
351
+ placeholder: options.placeholder || 'Powered by Seekora',
352
352
  showSuggestions: options.showSuggestions !== false,
353
353
  minQueryLength: options.minQueryLength || 1,
354
354
  maxSuggestions: options.maxSuggestions || 10,
@@ -360,8 +360,6 @@ class SearchBar {
360
360
  onBrandClick: options.onBrandClick,
361
361
  searchOptions: options.searchOptions,
362
362
  };
363
- // Cache credentials and environment from client for rich suggestions
364
- this.cacheClientCredentials();
365
363
  this.render();
366
364
  this.attachEventListeners();
367
365
  // Subscribe to state manager to sync input with query state
@@ -583,108 +581,58 @@ class SearchBar {
583
581
  }
584
582
  async fetchRichSuggestions(query) {
585
583
  try {
586
- // Use cached credentials first, then try to get from client
587
- let baseUrl = 'https://api.seekora.com';
588
- let storeId = this.cachedStoreId;
589
- let readSecret = this.cachedReadSecret;
590
- const env = this.cachedEnvironment;
591
- // If not cached, try to get from client
592
- const clientAny = this.client;
593
- if (!storeId || !readSecret) {
594
- if (clientAny.config) {
595
- storeId = storeId || clientAny.config.storeId;
596
- readSecret = readSecret || clientAny.config.readSecret;
597
- }
598
- else if (clientAny.storeId && clientAny.readSecret) {
599
- storeId = storeId || clientAny.storeId;
600
- readSecret = readSecret || clientAny.readSecret;
601
- }
602
- else if (clientAny._config) {
603
- storeId = storeId || clientAny._config.storeId;
604
- readSecret = readSecret || clientAny._config.readSecret;
605
- }
606
- else if (clientAny._storeId && clientAny._readSecret) {
607
- storeId = storeId || clientAny._storeId;
608
- readSecret = readSecret || clientAny._readSecret;
609
- }
610
- }
611
- // Determine environment and set baseUrl
612
- const environment = env || clientAny.environment || clientAny.config?.environment || clientAny._config?.environment;
613
- const isDevelopment = environment === 'development';
614
- // ALWAYS use localhost:3000 for development - FORCE IT
615
- baseUrl = 'http://localhost:3000'; // Force localhost for all requests in dev
616
- console.log('🌐 SearchBar: Setting baseUrl', {
617
- environment,
618
- isDevelopment,
619
- forcedBaseUrl: baseUrl,
620
- });
621
- if (!storeId || !readSecret) {
622
- log.warn('SearchBar: Missing store credentials, falling back to basic suggestions', {
623
- hasConfig: !!clientAny.config,
624
- hasDirectProps: !!(clientAny.storeId && clientAny.readSecret),
625
- hasPrivateConfig: !!clientAny._config,
626
- clientKeys: Object.keys(clientAny),
627
- });
628
- await this.fallbackToBasicSuggestions(query);
629
- return;
630
- }
631
- log.verbose('SearchBar: Fetching rich suggestions', {
632
- baseUrl,
633
- storeId: storeId ? storeId.substring(0, 8) + '...' : 'missing',
634
- query,
635
- environment,
636
- isDevelopment,
637
- credentialsFromCache: !!(this.cachedStoreId && this.cachedReadSecret),
584
+ log.verbose('SearchBar: Fetching rich suggestions via client.getSuggestions', { query });
585
+ const response = await this.client.getSuggestions(query, {
586
+ include_dropdown_recommendations: true,
587
+ hitsPerPage: this.options.maxSuggestions,
588
+ returnFullResponse: true,
638
589
  });
639
- // Build API URL with rich recommendations
640
- // Use 'query' parameter to match API expectations (also accepts 'q')
641
- // Empty query is allowed - will return trending products/brands
642
- const params = new URLSearchParams({
643
- include_dropdown_recommendations: 'true',
644
- hitsPerPage: String(this.options.maxSuggestions),
645
- });
646
- // Only add query parameter if it's not empty
647
- if (query && query.trim().length > 0) {
648
- params.append('query', query);
649
- }
650
- const url = `${baseUrl}/api/v1/suggestions/queries?${params.toString()}`;
651
- log.verbose('SearchBar: Making rich suggestions request', { url: url.replace(/secret=[^&]+/, 'secret=***') });
652
- const response = await fetch(url, {
653
- method: 'GET',
654
- headers: {
655
- 'x-storeid': storeId,
656
- 'x-storesecret': readSecret,
657
- 'Content-Type': 'application/json',
590
+ // response is QuerySuggestionsFullResponse when returnFullResponse is true
591
+ const suggestions = response.suggestions || [];
592
+ const extensions = response.extensions;
593
+ // Build RichQuerySuggestionsResponse from SDK response
594
+ const raw = response.raw || {};
595
+ const data = {
596
+ status: 'success',
597
+ data: {
598
+ hits: suggestions,
599
+ nbHits: suggestions.length,
600
+ page: raw.page || 0,
601
+ hitsPerPage: raw.hitsPerPage || this.options.maxSuggestions,
602
+ processingTimeMS: raw.processingTimeMS || 0,
603
+ query: query,
604
+ indexUsed: raw.indexUsed || '',
605
+ parsedQuery: raw.parsedQuery || query,
606
+ dropdown_recommendations: extensions ? {
607
+ trending_searches: extensions.trending_searches,
608
+ trending_products: extensions.trending_products,
609
+ popular_brands: extensions.popular_brands,
610
+ processing_time_ms: extensions.processing_time_ms || 0,
611
+ cached_at: extensions.cached_at,
612
+ } : undefined,
658
613
  },
659
- });
660
- if (!response.ok) {
661
- throw new Error(`API request failed: ${response.status} ${response.statusText}`);
662
- }
663
- const data = await response.json();
664
- if (data.status === 'error') {
665
- throw new Error('API returned error status');
666
- }
614
+ timestamp: raw.timestamp || new Date().toISOString(),
615
+ version: raw.version || '',
616
+ };
667
617
  this.richSuggestionsData = data;
668
618
  // Transform hits to SuggestionItem format
669
- this.suggestions = (data.data.hits || []).map((hit) => ({
619
+ this.suggestions = suggestions.map((hit) => ({
670
620
  query: hit.query,
671
621
  count: hit.popularity,
672
622
  metadata: hit,
673
623
  }));
674
- console.log('SearchBar: Rich suggestions loaded', {
624
+ log.verbose('SearchBar: Rich suggestions loaded', {
675
625
  query,
676
626
  suggestionsCount: this.suggestions.length,
677
627
  hasTrendingSearches: !!data.data.dropdown_recommendations?.trending_searches?.length,
678
628
  hasTrendingProducts: !!data.data.dropdown_recommendations?.trending_products?.length,
679
629
  hasPopularBrands: !!data.data.dropdown_recommendations?.popular_brands?.length,
680
- rawData: data.data.dropdown_recommendations,
681
630
  });
682
631
  }
683
632
  catch (err) {
684
633
  const error = err instanceof Error ? err : new Error(String(err));
685
634
  log.error('SearchBar: Failed to fetch rich suggestions, falling back to basic', {
686
635
  error: error.message,
687
- stack: error.stack,
688
636
  query,
689
637
  });
690
638
  await this.fallbackToBasicSuggestions(query);
@@ -713,50 +661,6 @@ class SearchBar {
713
661
  this.richSuggestionsData = null;
714
662
  }
715
663
  }
716
- cacheClientCredentials() {
717
- const clientAny = this.client;
718
- console.log('🔍 SearchBar: Attempting to cache credentials', {
719
- hasConfig: !!clientAny.config,
720
- hasDirectProps: !!(clientAny.storeId && clientAny.readSecret),
721
- hasPrivateConfig: !!clientAny._config,
722
- hasPrivateProps: !!(clientAny._storeId && clientAny._readSecret),
723
- clientKeys: Object.keys(clientAny).slice(0, 10),
724
- // Try to see actual values
725
- configStoreId: clientAny.config?.storeId,
726
- directStoreId: clientAny.storeId,
727
- });
728
- // Try multiple ways to extract credentials - check ALL properties
729
- if (clientAny.config && clientAny.config.storeId) {
730
- this.cachedStoreId = clientAny.config.storeId;
731
- this.cachedReadSecret = clientAny.config.readSecret;
732
- this.cachedEnvironment = clientAny.config.environment;
733
- console.log('📍 Extracted from config');
734
- }
735
- if (!this.cachedStoreId && clientAny.storeId) {
736
- this.cachedStoreId = clientAny.storeId;
737
- this.cachedReadSecret = clientAny.readSecret;
738
- this.cachedEnvironment = clientAny.environment;
739
- console.log('📍 Extracted from direct props');
740
- }
741
- if (!this.cachedStoreId && clientAny._config) {
742
- this.cachedStoreId = clientAny._config.storeId;
743
- this.cachedReadSecret = clientAny._config.readSecret;
744
- this.cachedEnvironment = clientAny._config.environment;
745
- console.log('📍 Extracted from _config');
746
- }
747
- if (!this.cachedStoreId && clientAny._storeId) {
748
- this.cachedStoreId = clientAny._storeId;
749
- this.cachedReadSecret = clientAny._readSecret;
750
- this.cachedEnvironment = clientAny._environment || clientAny.environment;
751
- console.log('📍 Extracted from _private props');
752
- }
753
- console.log('✅ SearchBar: Cached client credentials', {
754
- hasStoreId: !!this.cachedStoreId,
755
- storeIdPreview: this.cachedStoreId ? this.cachedStoreId.substring(0, 8) + '...' : 'MISSING',
756
- hasReadSecret: !!this.cachedReadSecret,
757
- environment: this.cachedEnvironment,
758
- });
759
- }
760
664
  async performSearch() {
761
665
  // Use empty string for empty queries
762
666
  const query = this.input.value.trim();
@@ -1241,7 +1145,6 @@ class SearchResults {
1241
1145
  onResultClick: options.onResultClick,
1242
1146
  renderResult: options.renderResult,
1243
1147
  renderEmpty: options.renderEmpty,
1244
- renderLoading: options.renderLoading,
1245
1148
  renderError: options.renderError,
1246
1149
  };
1247
1150
  // Attach event delegation listener to the persistent container for result clicks
@@ -1389,13 +1292,6 @@ class SearchResults {
1389
1292
  loading: this.options.loading,
1390
1293
  hasError: !!this.options.error,
1391
1294
  });
1392
- if (this.options.loading) {
1393
- const loadingEl = this.options.renderLoading
1394
- ? this.options.renderLoading()
1395
- : this.renderDefaultLoading();
1396
- this.container.appendChild(loadingEl);
1397
- return;
1398
- }
1399
1295
  if (this.options.error) {
1400
1296
  const errorEl = this.options.renderError
1401
1297
  ? this.options.renderError(this.options.error)
@@ -1490,12 +1386,6 @@ class SearchResults {
1490
1386
  };
1491
1387
  }
1492
1388
  }
1493
- renderDefaultLoading() {
1494
- const div = document.createElement('div');
1495
- div.style.cssText = this.getLoadingStyle();
1496
- div.textContent = 'Loading results...';
1497
- return div;
1498
- }
1499
1389
  renderDefaultError(error) {
1500
1390
  const div = document.createElement('div');
1501
1391
  div.style.cssText = this.getErrorStyle();
@@ -1615,13 +1505,6 @@ class SearchResults {
1615
1505
  get theme() {
1616
1506
  return this.provider.theme;
1617
1507
  }
1618
- getLoadingStyle() {
1619
- return `
1620
- padding: ${this.theme.spacing.large};
1621
- text-align: center;
1622
- color: ${this.theme.colors.text};
1623
- `;
1624
- }
1625
1508
  getErrorStyle() {
1626
1509
  return `
1627
1510
  padding: ${this.theme.spacing.large};
@@ -1799,9 +1682,6 @@ class Stats {
1799
1682
  }
1800
1683
  render() {
1801
1684
  this.container.innerHTML = '';
1802
- if (this.options.loading) {
1803
- return;
1804
- }
1805
1685
  const totalResults = this.getTotalResults();
1806
1686
  if (totalResults === null) {
1807
1687
  return;
@@ -3386,13 +3266,11 @@ class InfiniteHits {
3386
3266
  this.options = {
3387
3267
  renderHit: options.renderHit,
3388
3268
  renderEmpty: options.renderEmpty,
3389
- renderLoading: options.renderLoading,
3390
3269
  showMoreButton: options.showMoreButton !== false,
3391
3270
  useInfiniteScroll: options.useInfiniteScroll ?? false,
3392
3271
  scrollThreshold: options.scrollThreshold ?? 0.1,
3393
3272
  fieldMapping: options.fieldMapping,
3394
3273
  showMoreLabel: options.showMoreLabel ?? 'Show more',
3395
- loadingLabel: options.loadingLabel ?? 'Loading...',
3396
3274
  onHitClick: options.onHitClick,
3397
3275
  };
3398
3276
  // Subscribe to state manager
@@ -3457,10 +3335,6 @@ class InfiniteHits {
3457
3335
  const state = this.provider.stateManager.getState();
3458
3336
  // Initial loading state
3459
3337
  if (state.loading && this.accumulatedHits.length === 0) {
3460
- const loadingEl = this.options.renderLoading
3461
- ? this.options.renderLoading()
3462
- : this.createDefaultLoading();
3463
- this.container.appendChild(loadingEl);
3464
3338
  return;
3465
3339
  }
3466
3340
  // Empty state
@@ -3485,13 +3359,6 @@ class InfiniteHits {
3485
3359
  const button = this.createShowMoreButton();
3486
3360
  this.container.appendChild(button);
3487
3361
  }
3488
- // Loading more indicator
3489
- if (this.isLoadingMore) {
3490
- const loadingEl = this.options.renderLoading
3491
- ? this.options.renderLoading()
3492
- : this.createDefaultLoading();
3493
- this.container.appendChild(loadingEl);
3494
- }
3495
3362
  // Infinite scroll sentinel
3496
3363
  if (this.options.useInfiniteScroll && !this.isLastPage) {
3497
3364
  const sentinel = document.createElement('div');
@@ -3584,20 +3451,10 @@ class InfiniteHits {
3584
3451
  `;
3585
3452
  return empty;
3586
3453
  }
3587
- createDefaultLoading() {
3588
- const loading = document.createElement('div');
3589
- loading.textContent = this.options.loadingLabel;
3590
- loading.style.cssText = `
3591
- padding: ${this.theme.spacing.medium};
3592
- text-align: center;
3593
- color: ${this.theme.colors.textSecondary};
3594
- `;
3595
- return loading;
3596
- }
3597
3454
  createShowMoreButton() {
3598
3455
  const button = document.createElement('button');
3599
3456
  button.type = 'button';
3600
- button.textContent = this.isLoadingMore ? this.options.loadingLabel : this.options.showMoreLabel;
3457
+ button.textContent = this.options.showMoreLabel;
3601
3458
  button.disabled = this.isLoadingMore;
3602
3459
  button.style.cssText = this.getShowMoreButtonStyle();
3603
3460
  button.addEventListener('click', () => this.handleShowMore());
@@ -3902,7 +3759,6 @@ class QuerySuggestions {
3902
3759
  async loadSuggestions(query) {
3903
3760
  this.loading = true;
3904
3761
  this.error = null;
3905
- this.render();
3906
3762
  try {
3907
3763
  const response = await this.provider.client.getSuggestions(query, this.options.maxSuggestions);
3908
3764
  const rawSuggestions = Array.isArray(response) ? response : [];
@@ -3941,13 +3797,6 @@ class QuerySuggestions {
3941
3797
  if (!this.options.query || this.options.query.length < this.options.minQueryLength) {
3942
3798
  return;
3943
3799
  }
3944
- if (this.loading) {
3945
- const loadingDiv = document.createElement('div');
3946
- loadingDiv.style.cssText = this.getLoadingStyle();
3947
- loadingDiv.textContent = 'Loading suggestions...';
3948
- this.container.appendChild(loadingDiv);
3949
- return;
3950
- }
3951
3800
  if (this.error || this.suggestions.length === 0) {
3952
3801
  const emptyDiv = document.createElement('div');
3953
3802
  emptyDiv.style.cssText = this.getEmptyStyle();
@@ -4017,13 +3866,6 @@ class QuerySuggestions {
4017
3866
  color: ${this.theme.colors.text};
4018
3867
  `;
4019
3868
  }
4020
- getLoadingStyle() {
4021
- return `
4022
- padding: ${this.theme.spacing.medium};
4023
- text-align: center;
4024
- color: ${this.theme.colors.text};
4025
- `;
4026
- }
4027
3869
  getEmptyStyle() {
4028
3870
  return `
4029
3871
  padding: ${this.theme.spacing.medium};