@seekora-ai/ui-sdk-core 0.2.23 → 0.2.25
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.d.ts +4 -0
- package/dist/index.esm.js +43 -15
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +43 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -323,8 +323,11 @@ declare class SearchStateManager {
|
|
|
323
323
|
private state;
|
|
324
324
|
private listeners;
|
|
325
325
|
private debounceTimer;
|
|
326
|
+
private notifyScheduled;
|
|
326
327
|
private autoSearch;
|
|
327
328
|
private debounceMs;
|
|
329
|
+
private searchCoalesceTimer;
|
|
330
|
+
private searchCoalesceResolvers;
|
|
328
331
|
private defaultSearchOptions;
|
|
329
332
|
private keepResultsOnClear;
|
|
330
333
|
private abTestId?;
|
|
@@ -345,6 +348,7 @@ declare class SearchStateManager {
|
|
|
345
348
|
setSortBy(sortBy: string, triggerSearch?: boolean): void;
|
|
346
349
|
setItemsPerPage(itemsPerPage: number, triggerSearch?: boolean): void;
|
|
347
350
|
search(additionalOptions?: Partial<SearchOptions>): Promise<SearchResponse | null>;
|
|
351
|
+
private _executeSearch;
|
|
348
352
|
private buildSearchOptions;
|
|
349
353
|
private debouncedSearch;
|
|
350
354
|
subscribe(listener: (state: SearchState) => void): () => void;
|
package/dist/index.esm.js
CHANGED
|
@@ -1392,6 +1392,9 @@ class SearchStateManager {
|
|
|
1392
1392
|
constructor(config) {
|
|
1393
1393
|
this.listeners = [];
|
|
1394
1394
|
this.debounceTimer = null;
|
|
1395
|
+
this.notifyScheduled = false;
|
|
1396
|
+
this.searchCoalesceTimer = null;
|
|
1397
|
+
this.searchCoalesceResolvers = [];
|
|
1395
1398
|
this.client = config.client;
|
|
1396
1399
|
this.autoSearch = config.autoSearch !== false;
|
|
1397
1400
|
this.debounceMs = config.debounceMs || 300;
|
|
@@ -1536,13 +1539,27 @@ class SearchStateManager {
|
|
|
1536
1539
|
this.debouncedSearch();
|
|
1537
1540
|
}
|
|
1538
1541
|
}
|
|
1539
|
-
// Manual search trigger
|
|
1542
|
+
// Manual search trigger — coalesces rapid calls within 10ms into a single API request
|
|
1540
1543
|
async search(additionalOptions) {
|
|
1541
1544
|
// Clear debounce timer if exists
|
|
1542
1545
|
if (this.debounceTimer) {
|
|
1543
1546
|
clearTimeout(this.debounceTimer);
|
|
1544
1547
|
this.debounceTimer = null;
|
|
1545
1548
|
}
|
|
1549
|
+
return new Promise((resolve, reject) => {
|
|
1550
|
+
this.searchCoalesceResolvers.push({ resolve, reject });
|
|
1551
|
+
if (this.searchCoalesceTimer) {
|
|
1552
|
+
clearTimeout(this.searchCoalesceTimer);
|
|
1553
|
+
}
|
|
1554
|
+
this.searchCoalesceTimer = setTimeout(() => {
|
|
1555
|
+
this.searchCoalesceTimer = null;
|
|
1556
|
+
const resolvers = [...this.searchCoalesceResolvers];
|
|
1557
|
+
this.searchCoalesceResolvers = [];
|
|
1558
|
+
this._executeSearch(additionalOptions).then((result) => resolvers.forEach(r => r.resolve(result)), (err) => resolvers.forEach(r => r.reject(err)));
|
|
1559
|
+
}, 10);
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
async _executeSearch(additionalOptions) {
|
|
1546
1563
|
this.setState({ loading: true, error: null });
|
|
1547
1564
|
try {
|
|
1548
1565
|
const searchOptions = this.buildSearchOptions(additionalOptions);
|
|
@@ -1639,19 +1656,27 @@ class SearchStateManager {
|
|
|
1639
1656
|
this.state = { ...this.state, ...updates };
|
|
1640
1657
|
this.notifyListeners();
|
|
1641
1658
|
}
|
|
1642
|
-
// Notify all listeners of state changes
|
|
1659
|
+
// Notify all listeners of state changes, batched via microtask.
|
|
1660
|
+
// Multiple synchronous mutations (e.g. addRefinement + page reset)
|
|
1661
|
+
// coalesce into a single listener notification.
|
|
1643
1662
|
notifyListeners() {
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1663
|
+
if (this.notifyScheduled)
|
|
1664
|
+
return;
|
|
1665
|
+
this.notifyScheduled = true;
|
|
1666
|
+
queueMicrotask(() => {
|
|
1667
|
+
this.notifyScheduled = false;
|
|
1668
|
+
const state = this.getState();
|
|
1669
|
+
this.listeners.forEach(listener => {
|
|
1670
|
+
try {
|
|
1671
|
+
listener(state);
|
|
1672
|
+
}
|
|
1673
|
+
catch (err) {
|
|
1674
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1675
|
+
log.error('SearchStateManager: Error in listener', {
|
|
1676
|
+
error: error.message,
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
});
|
|
1655
1680
|
});
|
|
1656
1681
|
}
|
|
1657
1682
|
/** Explicitly clear results (bypasses keepResultsOnClear) */
|
|
@@ -1697,10 +1722,13 @@ class SearchStateManager {
|
|
|
1697
1722
|
async fetchFilters(options) {
|
|
1698
1723
|
log.verbose('SearchStateManager: Fetching filters', { options });
|
|
1699
1724
|
try {
|
|
1700
|
-
|
|
1725
|
+
// Do NOT pass refinement-based filters to the Filters API.
|
|
1726
|
+
// Facets should be generated from the search query only, not narrowed
|
|
1727
|
+
// by active filter selections. This keeps facet options stable when
|
|
1728
|
+
// users toggle filters (same behaviour as performSimplifiedFacetSearch
|
|
1729
|
+
// in the search API).
|
|
1701
1730
|
const response = await this.client.getFilters({
|
|
1702
1731
|
q: this.state.query || undefined,
|
|
1703
|
-
filter: filterString || undefined,
|
|
1704
1732
|
...options,
|
|
1705
1733
|
});
|
|
1706
1734
|
log.info('SearchStateManager: Filters fetched', {
|