bonsai-search 3.0.8

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.
@@ -0,0 +1,312 @@
1
+ //#region src/types.d.ts
2
+ /** Size configuration for srcset generation */
3
+ interface SrcSetSize {
4
+ /** Width in pixels */
5
+ width: number;
6
+ /** Height in pixels */
7
+ height: number;
8
+ /** Crop mode (e.g., 'crop_center', 'crop_top') */
9
+ crop: string;
10
+ }
11
+ /** Map of SDK class names to additional classes to add */
12
+ type ClassAdditions = Record<string, string[]>;
13
+ interface BonsaiSearchConfig {
14
+ /** The container element where the search UI will be rendered */
15
+ container: HTMLElement;
16
+ /** API key for authentication */
17
+ apiKey: string;
18
+ /** Tenant/Organization ID */
19
+ baseUrl?: string;
20
+ /** Placeholder text for search input */
21
+ placeholder?: string;
22
+ /** Array of search suggestion strings */
23
+ suggestions?: string[];
24
+ /** Debounce delay in milliseconds for search-as-you-type (0 = disabled) */
25
+ debounceMs?: number;
26
+ /** Maximum number of results to display */
27
+ maxResults?: number;
28
+ /** Request timeout in milliseconds */
29
+ timeoutMs?: number;
30
+ /** Hostname for image CDN (e.g., 'mmlafleur.com') - used for srcset generation */
31
+ imageHostname?: string;
32
+ /** Whether to generate srcset attributes for product images */
33
+ generateSrcSet?: boolean;
34
+ /** Array of sizes for srcset generation */
35
+ srcSetSizes?: SrcSetSize[];
36
+ /** Map of SDK class names to additional classes to add to those elements */
37
+ classAdditions?: ClassAdditions;
38
+ /** Whether to render price in result cards (default: false for backward compatibility) */
39
+ renderPrice?: boolean;
40
+ /** If true, show price with title in caption. If false, render price in separate element (default: true) */
41
+ renderPriceWithTitle?: boolean;
42
+ /** Callback to transform price before rendering (e.g., for formatting) */
43
+ onPrice?: (result: SearchResult, price: string, parent?: HTMLElement) => string;
44
+ /** Callback to customize image element after creation. sdk is the BonsaiSearch instance. */
45
+ onImg?: (result: SearchResult, imgElement: HTMLImageElement, wrapperElement: HTMLElement, sdk: any) => void;
46
+ /** Callback fired when search is initiated */
47
+ onSearch?: (query: string) => void;
48
+ /**
49
+ * Callback fired when initial results are received (from Meilisearch).
50
+ * In v3, this is called immediately when the "results" SSE event is received.
51
+ */
52
+ onResults?: (results: SearchResult[]) => void;
53
+ /**
54
+ * Callback fired when AI-scored results and recommendations are received.
55
+ * In v3, this is called when the "ai" SSE event is received (after LLM processing).
56
+ */
57
+ onAi?: (data: AiEventData) => void;
58
+ /** Callback fired when an error occurs */
59
+ onError?: (error: Error) => void;
60
+ /** Object-fit CSS property for result images. Accepts "cover" or "contain". Defaults to "cover". */
61
+ imageObjectFit?: "cover" | "contain";
62
+ /** Whether to enable markdown rendering for recommendation text. Defaults to false. */
63
+ markdown?: boolean;
64
+ /** Label for featured/recommended items section (default: "Featured Items") */
65
+ featuredItemsLabel?: string;
66
+ /** Label for additional items when recommendations exist (default: "More Items") */
67
+ moreItemsLabel?: string;
68
+ /** Label for items when no recommendations (default: "Items") */
69
+ itemsLabel?: string;
70
+ }
71
+ /** Data received from the "ai" SSE event */
72
+ interface AiEventData {
73
+ /** Whether the AI scoring was successful */
74
+ success: boolean;
75
+ /** AI recommendations */
76
+ recommendations: Recommendation[];
77
+ /** AI-scored results (filtered by minimum relevancy) */
78
+ results: SearchResult[];
79
+ /** Number of results after AI filtering */
80
+ count: number;
81
+ /** Maximum relevancy score across all results */
82
+ maxRelevance: number;
83
+ /** Error message if AI scoring failed */
84
+ error?: string;
85
+ }
86
+ /** Data received from the "results" SSE event */
87
+ interface ResultsEventData {
88
+ /** Whether the search was successful */
89
+ success: boolean;
90
+ /** The search query */
91
+ query: string;
92
+ /** Initial search results (before AI scoring) */
93
+ results: SearchResult[];
94
+ /** Number of results */
95
+ count: number;
96
+ /** Initial product count from Meilisearch */
97
+ initialProductCount: number;
98
+ /** Error message if search failed */
99
+ error?: string;
100
+ }
101
+ interface SearchResult {
102
+ id: string;
103
+ name: string;
104
+ handle: string;
105
+ vendor: string | null;
106
+ productType: string | null;
107
+ tags: string[];
108
+ vectorScore: number;
109
+ relevancyScore: number;
110
+ reasoning: string;
111
+ image: string | null;
112
+ price: string | null;
113
+ compareAtPrice: string | null;
114
+ description: string | null;
115
+ publicUrl: string;
116
+ type: "product" | "context";
117
+ }
118
+ interface Recommendation {
119
+ text: string;
120
+ productIds: string[];
121
+ relevancyScore: number;
122
+ reasoning: string;
123
+ }
124
+ interface SearchResponse {
125
+ success: boolean;
126
+ query: string;
127
+ hydeQuery: string;
128
+ hydeReasoning: string;
129
+ count: number;
130
+ results: SearchResult[];
131
+ recommendations?: Recommendation[];
132
+ error?: string;
133
+ }
134
+ interface Suggestion {
135
+ id: string;
136
+ suggestion: string;
137
+ }
138
+ //#endregion
139
+ //#region src/bonsai-search-webcomponent.d.ts
140
+ /**
141
+ * Web Component for Bonsai Search
142
+ * Fully encapsulated with Shadow DOM, no inherited styles
143
+ *
144
+ * Usage:
145
+ * <bonsai-search
146
+ * api-key="your-api-key"
147
+ * base-url="https://api.hibonsai.com/rest/search/v2/"
148
+ * placeholder="Describe what you're looking for..."
149
+ * suggestions='["suggestion 1", "suggestion 2"]'
150
+ * max-results="20"
151
+ * render-price
152
+ * brand-color="#0A5B3B"
153
+ * text-color="#303030"
154
+ * muted-color="#9CA3AF"
155
+ * input-bg="#f5f5f5"
156
+ * card-bg="#f5f5f5"
157
+ * image-object-fit="cover"
158
+ * featured-items-label="Featured Items"
159
+ * more-items-label="More Items"
160
+ * items-label="Items">
161
+ * </bonsai-search>
162
+ */
163
+ declare class BonsaiSearchElement extends HTMLElement {
164
+ private search;
165
+ private shadow;
166
+ private container;
167
+ static get observedAttributes(): string[];
168
+ constructor();
169
+ connectedCallback(): void;
170
+ disconnectedCallback(): void;
171
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
172
+ private render;
173
+ private updateStyles;
174
+ private initialize;
175
+ setSuggestion(suggestion: string): void;
176
+ clear(): void;
177
+ focus(): void;
178
+ private getDefaultCSS;
179
+ }
180
+ //#endregion
181
+ //#region src/bonsai-searchbar-webcomponent.d.ts
182
+ /**
183
+ * Web Component for Bonsai Search Bar
184
+ * Fully encapsulated with Shadow DOM, no inherited styles
185
+ *
186
+ * Usage:
187
+ * <bonsai-searchbar
188
+ * search-path="/ai-search"
189
+ * placeholder="Describe what you're looking for..."
190
+ * suggestions='["suggestion 1", "suggestion 2"]'
191
+ * brand-color="#0A5B3B"
192
+ * text-color="#303030"
193
+ * muted-color="#9CA3AF"
194
+ * input-background="#f5f5f5"
195
+ * input-opacity="1"
196
+ * close-button>
197
+ * </bonsai-searchbar>
198
+ */
199
+ declare class BonsaiSearchBarElement extends HTMLElement {
200
+ private searchBar;
201
+ private shadow;
202
+ private container;
203
+ static get observedAttributes(): string[];
204
+ constructor();
205
+ connectedCallback(): void;
206
+ disconnectedCallback(): void;
207
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
208
+ private render;
209
+ private updateStyles;
210
+ private initialize;
211
+ setQuery(query: string): void;
212
+ submit(): void;
213
+ clear(): void;
214
+ private getDefaultCSS;
215
+ }
216
+ //#endregion
217
+ //#region src/index.d.ts
218
+ declare class BonsaiSearch {
219
+ private config;
220
+ private state;
221
+ private container;
222
+ private searchBar;
223
+ private searchInput;
224
+ private actionsContainer;
225
+ private submitBtn;
226
+ private loadingState;
227
+ private loadingTextInner;
228
+ private doneState;
229
+ private resetBtn;
230
+ private suggestionsDropdown;
231
+ private poweredBy;
232
+ private resultsContainer;
233
+ private query;
234
+ private loadingIndex;
235
+ private loadingInterval;
236
+ private debounceTimer;
237
+ private abortController;
238
+ private loadingStates;
239
+ constructor(config: BonsaiSearchConfig);
240
+ /** Get the SDK version */
241
+ static get version(): string;
242
+ /** Infer base URL from script tag or use current origin */
243
+ private inferBaseUrl;
244
+ /** Build class name string with any configured additional classes */
245
+ private buildClassName;
246
+ /** Apply a shadow part name for external styling */
247
+ private applyPart;
248
+ /** Validate configuration */
249
+ private validateConfig;
250
+ /** Render the search UI */
251
+ private render;
252
+ /** Render suggestions in the dropdown */
253
+ private renderSuggestions;
254
+ /** Attach event listeners */
255
+ private attachEventListeners;
256
+ /** Handle input focus */
257
+ private handleFocus;
258
+ /** Handle input blur */
259
+ private handleBlur;
260
+ /** Handle input change */
261
+ private handleInput;
262
+ /** Handle key down */
263
+ private handleKeyDown;
264
+ /** Handle suggestion click */
265
+ private handleSuggestionClick;
266
+ /** Handle search submit using Server-Sent Events */
267
+ private handleSubmit;
268
+ /** Parse SSE events from a buffer string */
269
+ private parseSSEEvents;
270
+ /** Handle reset */
271
+ private handleReset;
272
+ /** Set the current state and update UI */
273
+ private setState;
274
+ /** Update action buttons visibility based on state */
275
+ private updateActionButtons;
276
+ /** Update input state (disabled only during loading) */
277
+ private updateInputState;
278
+ /** Start loading animation */
279
+ private startLoadingAnimation;
280
+ /** Update loading text position */
281
+ private updateLoadingText;
282
+ /** Stop loading animation */
283
+ private stopLoadingAnimation;
284
+ /** Show recommendations loading indicator */
285
+ private showRecommendationsLoading;
286
+ /** Hide recommendations loading indicator */
287
+ private hideRecommendationsLoading;
288
+ /** Render search results */
289
+ private renderResults;
290
+ /** Generate srcset attribute for an image URL */
291
+ private getSrcSet;
292
+ /** Resolve an image value that may be a string URL or an object with sourceUrl/source_url */
293
+ private resolveImageUrl;
294
+ /** Create a result card */
295
+ private createResultCard;
296
+ /** Render empty state */
297
+ private renderEmpty;
298
+ /** Render error state */
299
+ private renderError;
300
+ /** Check for query parameter in URL or localStorage */
301
+ private checkForQueryParam;
302
+ /** Set a suggestion programmatically and trigger search */
303
+ setSuggestion(suggestion: string): void;
304
+ /** Clear the search and results */
305
+ clear(): void;
306
+ /** Focus the search input */
307
+ focus(): void;
308
+ /** Destroy the instance and clean up */
309
+ destroy(): void;
310
+ }
311
+ //#endregion
312
+ export { AiEventData, BonsaiSearch, BonsaiSearchBarElement, BonsaiSearchConfig, BonsaiSearchElement, ClassAdditions, Recommendation, ResultsEventData, SearchResponse, SearchResult, SrcSetSize, Suggestion };
@@ -0,0 +1,312 @@
1
+ //#region src/types.d.ts
2
+ /** Size configuration for srcset generation */
3
+ interface SrcSetSize {
4
+ /** Width in pixels */
5
+ width: number;
6
+ /** Height in pixels */
7
+ height: number;
8
+ /** Crop mode (e.g., 'crop_center', 'crop_top') */
9
+ crop: string;
10
+ }
11
+ /** Map of SDK class names to additional classes to add */
12
+ type ClassAdditions = Record<string, string[]>;
13
+ interface BonsaiSearchConfig {
14
+ /** The container element where the search UI will be rendered */
15
+ container: HTMLElement;
16
+ /** API key for authentication */
17
+ apiKey: string;
18
+ /** Tenant/Organization ID */
19
+ baseUrl?: string;
20
+ /** Placeholder text for search input */
21
+ placeholder?: string;
22
+ /** Array of search suggestion strings */
23
+ suggestions?: string[];
24
+ /** Debounce delay in milliseconds for search-as-you-type (0 = disabled) */
25
+ debounceMs?: number;
26
+ /** Maximum number of results to display */
27
+ maxResults?: number;
28
+ /** Request timeout in milliseconds */
29
+ timeoutMs?: number;
30
+ /** Hostname for image CDN (e.g., 'mmlafleur.com') - used for srcset generation */
31
+ imageHostname?: string;
32
+ /** Whether to generate srcset attributes for product images */
33
+ generateSrcSet?: boolean;
34
+ /** Array of sizes for srcset generation */
35
+ srcSetSizes?: SrcSetSize[];
36
+ /** Map of SDK class names to additional classes to add to those elements */
37
+ classAdditions?: ClassAdditions;
38
+ /** Whether to render price in result cards (default: false for backward compatibility) */
39
+ renderPrice?: boolean;
40
+ /** If true, show price with title in caption. If false, render price in separate element (default: true) */
41
+ renderPriceWithTitle?: boolean;
42
+ /** Callback to transform price before rendering (e.g., for formatting) */
43
+ onPrice?: (result: SearchResult, price: string, parent?: HTMLElement) => string;
44
+ /** Callback to customize image element after creation. sdk is the BonsaiSearch instance. */
45
+ onImg?: (result: SearchResult, imgElement: HTMLImageElement, wrapperElement: HTMLElement, sdk: any) => void;
46
+ /** Callback fired when search is initiated */
47
+ onSearch?: (query: string) => void;
48
+ /**
49
+ * Callback fired when initial results are received (from Meilisearch).
50
+ * In v3, this is called immediately when the "results" SSE event is received.
51
+ */
52
+ onResults?: (results: SearchResult[]) => void;
53
+ /**
54
+ * Callback fired when AI-scored results and recommendations are received.
55
+ * In v3, this is called when the "ai" SSE event is received (after LLM processing).
56
+ */
57
+ onAi?: (data: AiEventData) => void;
58
+ /** Callback fired when an error occurs */
59
+ onError?: (error: Error) => void;
60
+ /** Object-fit CSS property for result images. Accepts "cover" or "contain". Defaults to "cover". */
61
+ imageObjectFit?: "cover" | "contain";
62
+ /** Whether to enable markdown rendering for recommendation text. Defaults to false. */
63
+ markdown?: boolean;
64
+ /** Label for featured/recommended items section (default: "Featured Items") */
65
+ featuredItemsLabel?: string;
66
+ /** Label for additional items when recommendations exist (default: "More Items") */
67
+ moreItemsLabel?: string;
68
+ /** Label for items when no recommendations (default: "Items") */
69
+ itemsLabel?: string;
70
+ }
71
+ /** Data received from the "ai" SSE event */
72
+ interface AiEventData {
73
+ /** Whether the AI scoring was successful */
74
+ success: boolean;
75
+ /** AI recommendations */
76
+ recommendations: Recommendation[];
77
+ /** AI-scored results (filtered by minimum relevancy) */
78
+ results: SearchResult[];
79
+ /** Number of results after AI filtering */
80
+ count: number;
81
+ /** Maximum relevancy score across all results */
82
+ maxRelevance: number;
83
+ /** Error message if AI scoring failed */
84
+ error?: string;
85
+ }
86
+ /** Data received from the "results" SSE event */
87
+ interface ResultsEventData {
88
+ /** Whether the search was successful */
89
+ success: boolean;
90
+ /** The search query */
91
+ query: string;
92
+ /** Initial search results (before AI scoring) */
93
+ results: SearchResult[];
94
+ /** Number of results */
95
+ count: number;
96
+ /** Initial product count from Meilisearch */
97
+ initialProductCount: number;
98
+ /** Error message if search failed */
99
+ error?: string;
100
+ }
101
+ interface SearchResult {
102
+ id: string;
103
+ name: string;
104
+ handle: string;
105
+ vendor: string | null;
106
+ productType: string | null;
107
+ tags: string[];
108
+ vectorScore: number;
109
+ relevancyScore: number;
110
+ reasoning: string;
111
+ image: string | null;
112
+ price: string | null;
113
+ compareAtPrice: string | null;
114
+ description: string | null;
115
+ publicUrl: string;
116
+ type: "product" | "context";
117
+ }
118
+ interface Recommendation {
119
+ text: string;
120
+ productIds: string[];
121
+ relevancyScore: number;
122
+ reasoning: string;
123
+ }
124
+ interface SearchResponse {
125
+ success: boolean;
126
+ query: string;
127
+ hydeQuery: string;
128
+ hydeReasoning: string;
129
+ count: number;
130
+ results: SearchResult[];
131
+ recommendations?: Recommendation[];
132
+ error?: string;
133
+ }
134
+ interface Suggestion {
135
+ id: string;
136
+ suggestion: string;
137
+ }
138
+ //#endregion
139
+ //#region src/bonsai-search-webcomponent.d.ts
140
+ /**
141
+ * Web Component for Bonsai Search
142
+ * Fully encapsulated with Shadow DOM, no inherited styles
143
+ *
144
+ * Usage:
145
+ * <bonsai-search
146
+ * api-key="your-api-key"
147
+ * base-url="https://api.hibonsai.com/rest/search/v2/"
148
+ * placeholder="Describe what you're looking for..."
149
+ * suggestions='["suggestion 1", "suggestion 2"]'
150
+ * max-results="20"
151
+ * render-price
152
+ * brand-color="#0A5B3B"
153
+ * text-color="#303030"
154
+ * muted-color="#9CA3AF"
155
+ * input-bg="#f5f5f5"
156
+ * card-bg="#f5f5f5"
157
+ * image-object-fit="cover"
158
+ * featured-items-label="Featured Items"
159
+ * more-items-label="More Items"
160
+ * items-label="Items">
161
+ * </bonsai-search>
162
+ */
163
+ declare class BonsaiSearchElement extends HTMLElement {
164
+ private search;
165
+ private shadow;
166
+ private container;
167
+ static get observedAttributes(): string[];
168
+ constructor();
169
+ connectedCallback(): void;
170
+ disconnectedCallback(): void;
171
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
172
+ private render;
173
+ private updateStyles;
174
+ private initialize;
175
+ setSuggestion(suggestion: string): void;
176
+ clear(): void;
177
+ focus(): void;
178
+ private getDefaultCSS;
179
+ }
180
+ //#endregion
181
+ //#region src/bonsai-searchbar-webcomponent.d.ts
182
+ /**
183
+ * Web Component for Bonsai Search Bar
184
+ * Fully encapsulated with Shadow DOM, no inherited styles
185
+ *
186
+ * Usage:
187
+ * <bonsai-searchbar
188
+ * search-path="/ai-search"
189
+ * placeholder="Describe what you're looking for..."
190
+ * suggestions='["suggestion 1", "suggestion 2"]'
191
+ * brand-color="#0A5B3B"
192
+ * text-color="#303030"
193
+ * muted-color="#9CA3AF"
194
+ * input-background="#f5f5f5"
195
+ * input-opacity="1"
196
+ * close-button>
197
+ * </bonsai-searchbar>
198
+ */
199
+ declare class BonsaiSearchBarElement extends HTMLElement {
200
+ private searchBar;
201
+ private shadow;
202
+ private container;
203
+ static get observedAttributes(): string[];
204
+ constructor();
205
+ connectedCallback(): void;
206
+ disconnectedCallback(): void;
207
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
208
+ private render;
209
+ private updateStyles;
210
+ private initialize;
211
+ setQuery(query: string): void;
212
+ submit(): void;
213
+ clear(): void;
214
+ private getDefaultCSS;
215
+ }
216
+ //#endregion
217
+ //#region src/index.d.ts
218
+ declare class BonsaiSearch {
219
+ private config;
220
+ private state;
221
+ private container;
222
+ private searchBar;
223
+ private searchInput;
224
+ private actionsContainer;
225
+ private submitBtn;
226
+ private loadingState;
227
+ private loadingTextInner;
228
+ private doneState;
229
+ private resetBtn;
230
+ private suggestionsDropdown;
231
+ private poweredBy;
232
+ private resultsContainer;
233
+ private query;
234
+ private loadingIndex;
235
+ private loadingInterval;
236
+ private debounceTimer;
237
+ private abortController;
238
+ private loadingStates;
239
+ constructor(config: BonsaiSearchConfig);
240
+ /** Get the SDK version */
241
+ static get version(): string;
242
+ /** Infer base URL from script tag or use current origin */
243
+ private inferBaseUrl;
244
+ /** Build class name string with any configured additional classes */
245
+ private buildClassName;
246
+ /** Apply a shadow part name for external styling */
247
+ private applyPart;
248
+ /** Validate configuration */
249
+ private validateConfig;
250
+ /** Render the search UI */
251
+ private render;
252
+ /** Render suggestions in the dropdown */
253
+ private renderSuggestions;
254
+ /** Attach event listeners */
255
+ private attachEventListeners;
256
+ /** Handle input focus */
257
+ private handleFocus;
258
+ /** Handle input blur */
259
+ private handleBlur;
260
+ /** Handle input change */
261
+ private handleInput;
262
+ /** Handle key down */
263
+ private handleKeyDown;
264
+ /** Handle suggestion click */
265
+ private handleSuggestionClick;
266
+ /** Handle search submit using Server-Sent Events */
267
+ private handleSubmit;
268
+ /** Parse SSE events from a buffer string */
269
+ private parseSSEEvents;
270
+ /** Handle reset */
271
+ private handleReset;
272
+ /** Set the current state and update UI */
273
+ private setState;
274
+ /** Update action buttons visibility based on state */
275
+ private updateActionButtons;
276
+ /** Update input state (disabled only during loading) */
277
+ private updateInputState;
278
+ /** Start loading animation */
279
+ private startLoadingAnimation;
280
+ /** Update loading text position */
281
+ private updateLoadingText;
282
+ /** Stop loading animation */
283
+ private stopLoadingAnimation;
284
+ /** Show recommendations loading indicator */
285
+ private showRecommendationsLoading;
286
+ /** Hide recommendations loading indicator */
287
+ private hideRecommendationsLoading;
288
+ /** Render search results */
289
+ private renderResults;
290
+ /** Generate srcset attribute for an image URL */
291
+ private getSrcSet;
292
+ /** Resolve an image value that may be a string URL or an object with sourceUrl/source_url */
293
+ private resolveImageUrl;
294
+ /** Create a result card */
295
+ private createResultCard;
296
+ /** Render empty state */
297
+ private renderEmpty;
298
+ /** Render error state */
299
+ private renderError;
300
+ /** Check for query parameter in URL or localStorage */
301
+ private checkForQueryParam;
302
+ /** Set a suggestion programmatically and trigger search */
303
+ setSuggestion(suggestion: string): void;
304
+ /** Clear the search and results */
305
+ clear(): void;
306
+ /** Focus the search input */
307
+ focus(): void;
308
+ /** Destroy the instance and clean up */
309
+ destroy(): void;
310
+ }
311
+ //#endregion
312
+ export { AiEventData, BonsaiSearch, BonsaiSearchBarElement, BonsaiSearchConfig, BonsaiSearchElement, ClassAdditions, Recommendation, ResultsEventData, SearchResponse, SearchResult, SrcSetSize, Suggestion };