@86d-app/search 0.0.3 → 0.0.6

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.
Files changed (93) hide show
  1. package/.turbo/turbo-build.log +1 -0
  2. package/AGENTS.md +72 -0
  3. package/README.md +172 -30
  4. package/dist/__tests__/controllers.test.d.ts +2 -0
  5. package/dist/__tests__/controllers.test.d.ts.map +1 -0
  6. package/dist/__tests__/embedding-provider.test.d.ts +2 -0
  7. package/dist/__tests__/embedding-provider.test.d.ts.map +1 -0
  8. package/dist/__tests__/endpoint-security.test.d.ts +2 -0
  9. package/dist/__tests__/endpoint-security.test.d.ts.map +1 -0
  10. package/dist/__tests__/meilisearch-provider.test.d.ts +2 -0
  11. package/dist/__tests__/meilisearch-provider.test.d.ts.map +1 -0
  12. package/dist/__tests__/service-impl.test.d.ts +2 -0
  13. package/dist/__tests__/service-impl.test.d.ts.map +1 -0
  14. package/dist/admin/components/index.d.ts +2 -0
  15. package/dist/admin/components/index.d.ts.map +1 -0
  16. package/dist/admin/components/search-analytics.d.ts +2 -0
  17. package/dist/admin/components/search-analytics.d.ts.map +1 -0
  18. package/dist/admin/endpoints/analytics.d.ts +15 -0
  19. package/dist/admin/endpoints/analytics.d.ts.map +1 -0
  20. package/dist/admin/endpoints/bulk-index.d.ts +20 -0
  21. package/dist/admin/endpoints/bulk-index.d.ts.map +1 -0
  22. package/dist/admin/endpoints/click-analytics.d.ts +7 -0
  23. package/dist/admin/endpoints/click-analytics.d.ts.map +1 -0
  24. package/dist/admin/endpoints/get-settings.d.ts +17 -0
  25. package/dist/admin/endpoints/get-settings.d.ts.map +1 -0
  26. package/dist/admin/endpoints/index-manage.d.ts +26 -0
  27. package/dist/admin/endpoints/index-manage.d.ts.map +1 -0
  28. package/dist/admin/endpoints/index.d.ts +125 -0
  29. package/dist/admin/endpoints/index.d.ts.map +1 -0
  30. package/dist/admin/endpoints/popular.d.ts +10 -0
  31. package/dist/admin/endpoints/popular.d.ts.map +1 -0
  32. package/dist/admin/endpoints/synonyms.d.ts +30 -0
  33. package/dist/admin/endpoints/synonyms.d.ts.map +1 -0
  34. package/dist/admin/endpoints/zero-results.d.ts +10 -0
  35. package/dist/admin/endpoints/zero-results.d.ts.map +1 -0
  36. package/dist/embedding-provider.d.ts +28 -0
  37. package/dist/embedding-provider.d.ts.map +1 -0
  38. package/dist/index.d.ts +23 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/meilisearch-provider.d.ts +104 -0
  41. package/dist/meilisearch-provider.d.ts.map +1 -0
  42. package/dist/schema.d.ts +133 -0
  43. package/dist/schema.d.ts.map +1 -0
  44. package/dist/service-impl.d.ts +6 -0
  45. package/dist/service-impl.d.ts.map +1 -0
  46. package/dist/service.d.ts +127 -0
  47. package/dist/service.d.ts.map +1 -0
  48. package/dist/store/components/_hooks.d.ts +6 -0
  49. package/dist/store/components/_hooks.d.ts.map +1 -0
  50. package/dist/store/components/index.d.ts +10 -0
  51. package/dist/store/components/index.d.ts.map +1 -0
  52. package/dist/store/components/search-bar.d.ts +7 -0
  53. package/dist/store/components/search-bar.d.ts.map +1 -0
  54. package/dist/store/components/search-page.d.ts +4 -0
  55. package/dist/store/components/search-page.d.ts.map +1 -0
  56. package/dist/store/components/search-results.d.ts +9 -0
  57. package/dist/store/components/search-results.d.ts.map +1 -0
  58. package/dist/store/endpoints/click.d.ts +14 -0
  59. package/dist/store/endpoints/click.d.ts.map +1 -0
  60. package/dist/store/endpoints/index.d.ts +85 -0
  61. package/dist/store/endpoints/index.d.ts.map +1 -0
  62. package/dist/store/endpoints/recent.d.ts +15 -0
  63. package/dist/store/endpoints/recent.d.ts.map +1 -0
  64. package/dist/store/endpoints/search.d.ts +36 -0
  65. package/dist/store/endpoints/search.d.ts.map +1 -0
  66. package/dist/store/endpoints/store-search.d.ts +16 -0
  67. package/dist/store/endpoints/store-search.d.ts.map +1 -0
  68. package/dist/store/endpoints/suggest.d.ts +11 -0
  69. package/dist/store/endpoints/suggest.d.ts.map +1 -0
  70. package/package.json +3 -3
  71. package/src/__tests__/controllers.test.ts +1026 -0
  72. package/src/__tests__/embedding-provider.test.ts +195 -0
  73. package/src/__tests__/endpoint-security.test.ts +300 -0
  74. package/src/__tests__/meilisearch-provider.test.ts +400 -0
  75. package/src/__tests__/service-impl.test.ts +341 -8
  76. package/src/admin/components/search-analytics.tsx +120 -0
  77. package/src/admin/endpoints/bulk-index.ts +34 -0
  78. package/src/admin/endpoints/click-analytics.ts +16 -0
  79. package/src/admin/endpoints/get-settings.ts +56 -0
  80. package/src/admin/endpoints/index-manage.ts +4 -1
  81. package/src/admin/endpoints/index.ts +6 -0
  82. package/src/admin/endpoints/synonyms.ts +1 -1
  83. package/src/embedding-provider.ts +99 -0
  84. package/src/index.ts +60 -4
  85. package/src/meilisearch-provider.ts +239 -0
  86. package/src/schema.ts +15 -0
  87. package/src/service-impl.ts +605 -34
  88. package/src/service.ts +60 -1
  89. package/src/store/endpoints/click.ts +21 -0
  90. package/src/store/endpoints/index.ts +2 -0
  91. package/src/store/endpoints/search.ts +38 -10
  92. package/src/store/endpoints/suggest.ts +2 -2
  93. package/vitest.config.ts +2 -0
@@ -0,0 +1 @@
1
+ $ tsc
package/AGENTS.md ADDED
@@ -0,0 +1,72 @@
1
+ # Search Module
2
+
3
+ In-memory full-text search with fuzzy matching, faceted filtering, click tracking, and query analytics.
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ src/
9
+ index.ts Factory: search(options?) => Module
10
+ schema.ts Data models: searchIndex, searchQuery, searchSynonym, searchClick
11
+ service.ts SearchController interface + types (SearchResult, SearchFacets, SearchClick, etc.)
12
+ service-impl.ts SearchController implementation (fuzzy, Levenshtein, highlights, facets)
13
+ store/
14
+ components/ Store-facing TSX (search bar, page, results)
15
+ endpoints/
16
+ store-search.ts GET /search/store-search (search integration)
17
+ search.ts GET /search (full-text with sort, tags, fuzzy, facets, did-you-mean)
18
+ suggest.ts GET /search/suggest
19
+ recent.ts GET /search/recent
20
+ click.ts POST /search/click (click tracking)
21
+ admin/
22
+ components/ Admin TSX (analytics dashboard)
23
+ endpoints/
24
+ analytics.ts GET /admin/search/analytics (includes CTR + avg click position)
25
+ popular.ts GET /admin/search/popular
26
+ zero-results.ts GET /admin/search/zero-results
27
+ click-analytics.ts GET /admin/search/clicks
28
+ synonyms.ts GET /admin/search/synonyms
29
+ POST /admin/search/synonyms/add
30
+ POST /admin/search/synonyms/:id/delete
31
+ index-manage.ts POST /admin/search/index
32
+ POST /admin/search/index/remove
33
+ bulk-index.ts POST /admin/search/index/bulk (up to 500 items)
34
+ ```
35
+
36
+ ## Options
37
+
38
+ ```ts
39
+ SearchOptions {
40
+ maxResults?: number
41
+ }
42
+ ```
43
+
44
+ ## Data models
45
+
46
+ - **searchIndex**: id, entityType, entityId, title, body?, tags (json[]), url, image?, metadata (json), indexedAt
47
+ - **searchQuery**: id, term, normalizedTerm, resultCount, sessionId?, searchedAt
48
+ - **searchSynonym**: id, term, synonyms (json[]), createdAt
49
+ - **searchClick**: id, queryId, term, entityType, entityId, position, clickedAt
50
+
51
+ ## Events
52
+
53
+ - Emits: `search.queried`, `search.indexed`, `search.removed`, `search.clicked`
54
+
55
+ ## Patterns
56
+
57
+ - Registers `search: { store: "/search/store-search" }` for cross-module search integration
58
+ - Registers store page at `/search` (SearchPage component)
59
+ - `indexItem` uses composite key `${entityType}_${entityId}` for deduplication; re-indexing updates in-place
60
+ - Different entityTypes with same entityId are separate index entries
61
+ - **Fuzzy search**: Levenshtein distance matching on title/tag/body tokens. Edit tolerance: 0 for ≤3 chars, 1 for 4-5 chars, 2 for 6+ chars. Enabled by default, disable with `fuzzy: false`
62
+ - **Scoring**: exact title (100) > title prefix (50) > tag exact (30) > title substring (25) > fuzzy title (15) > tag substring (15) > body (10) > fuzzy tag (8) > fuzzy body (5)
63
+ - **Sorting**: relevance (default), newest, oldest, title_asc, title_desc
64
+ - **Facets**: search results include entityType counts and tag counts (top 20)
65
+ - **Tag filtering**: pass `tags` option to filter results to items matching any specified tag
66
+ - **Highlights**: results include `<mark>` wrapped text in title and body for matched terms
67
+ - **Did-you-mean**: when a search returns zero results, suggests corrections using Levenshtein distance against indexed titles and popular search terms
68
+ - **Click tracking**: `recordClick()` stores query-to-click data; analytics includes CTR and avg click position
69
+ - **Bulk indexing**: `bulkIndex()` accepts up to 500 items, returns `{indexed, errors}` counts
70
+ - `recordQuery()` logs each search for analytics (popular terms, zero-result tracking)
71
+ - `suggest(prefix)` returns autocomplete: popular terms with results first, then matching index titles, deduplicated
72
+ - Synonyms are bidirectional: if "tee" → ["t-shirt"], then searching "tee" or "t-shirt" finds both
package/README.md CHANGED
@@ -9,18 +9,17 @@
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <a href="https://vercel.com/changelog"><strong>npm</strong></a> ·
13
12
  <a href="https://x.com/86d_app"><strong>X</strong></a> ·
14
- <a href="https://vercel.com/templates"><strong>LinkedIn</strong></a>
13
+ <a href="https://www.linkedin.com/company/86d"><strong>LinkedIn</strong></a>
15
14
  </p>
16
15
  <br/>
17
16
 
18
17
  > [!WARNING]
19
18
  > This project is under active development and is not ready for production use. Please proceed with caution. Use at your own risk.
20
19
 
21
- # @86d-app/search
20
+ # Search Module
22
21
 
23
- Unified search, autocomplete, and search analytics module for 86d commerce platform.
22
+ Full-text search with fuzzy matching, faceted filtering, autocomplete, click tracking, and search analytics for 86d commerce platform.
24
23
 
25
24
  ## Installation
26
25
 
@@ -48,55 +47,128 @@ const module = search({
48
47
 
49
48
  | Method | Path | Description |
50
49
  |---|---|---|
51
- | `GET` | `/search?q=...&type=...&limit=...&skip=...` | Full-text search with optional entity type filtering |
52
- | `GET` | `/search/suggest?prefix=...&limit=...` | Autocomplete suggestions |
50
+ | `GET` | `/search?q=...&type=...&tags=...&sort=...&fuzzy=...&limit=...&skip=...` | Full-text search with facets, sorting, fuzzy matching, and did-you-mean |
51
+ | `GET` | `/search/suggest?q=...&limit=...` | Autocomplete suggestions |
53
52
  | `GET` | `/search/recent?sessionId=...&limit=...` | Recent search queries by session |
53
+ | `POST` | `/search/click` | Record a search result click (queryId, term, entityType, entityId, position) |
54
+
55
+ ### Search query parameters
56
+
57
+ | Param | Type | Default | Description |
58
+ |---|---|---|---|
59
+ | `q` | `string` | required | Search query text |
60
+ | `type` | `string` | — | Filter by entity type |
61
+ | `tags` | `string` | — | Comma-separated tag filter |
62
+ | `sort` | `string` | `relevance` | Sort: `relevance`, `newest`, `oldest`, `title_asc`, `title_desc` |
63
+ | `fuzzy` | `boolean` | `true` | Enable fuzzy/typo-tolerant matching |
64
+ | `limit` | `number` | `20` | Results per page (max 100) |
65
+ | `skip` | `number` | `0` | Offset for pagination |
66
+ | `sessionId` | `string` | — | Session ID for analytics tracking |
67
+
68
+ ### Search response
69
+
70
+ ```ts
71
+ {
72
+ results: Array<{
73
+ id: string;
74
+ entityType: string;
75
+ entityId: string;
76
+ title: string;
77
+ url: string;
78
+ image?: string;
79
+ tags: string[];
80
+ score: number;
81
+ highlights?: { title?: string; body?: string };
82
+ }>;
83
+ total: number;
84
+ facets: {
85
+ entityTypes: Array<{ type: string; count: number }>;
86
+ tags: Array<{ tag: string; count: number }>;
87
+ };
88
+ didYouMean?: string;
89
+ }
90
+ ```
54
91
 
55
92
  ## Admin Endpoints
56
93
 
57
94
  | Method | Path | Description |
58
95
  |---|---|---|
59
- | `GET` | `/admin/search/analytics` | Search analytics summary |
96
+ | `GET` | `/admin/search/analytics` | Search analytics summary (includes CTR and avg click position) |
60
97
  | `GET` | `/admin/search/popular` | Most popular search terms |
61
98
  | `GET` | `/admin/search/zero-results` | Queries that returned zero results |
99
+ | `GET` | `/admin/search/clicks` | Click-through rate analytics |
62
100
  | `GET` | `/admin/search/synonyms` | List all synonym groups |
63
101
  | `POST` | `/admin/search/synonyms/add` | Add a synonym group |
64
102
  | `POST` | `/admin/search/synonyms/:id/delete` | Delete a synonym group |
65
103
  | `POST` | `/admin/search/index` | Manually index an item |
66
104
  | `POST` | `/admin/search/index/remove` | Remove an item from the index |
105
+ | `POST` | `/admin/search/index/bulk` | Bulk index up to 500 items |
67
106
 
68
107
  ## Controller API
69
108
 
70
109
  ```ts
71
110
  interface SearchController {
111
+ // Indexing
72
112
  indexItem(params: {
73
113
  entityType: string;
74
114
  entityId: string;
75
115
  title: string;
76
116
  body?: string;
77
117
  tags?: string[];
78
- url?: string;
118
+ url: string;
79
119
  image?: string;
80
120
  metadata?: Record<string, unknown>;
81
121
  }): Promise<SearchIndexItem>;
82
122
 
83
- removeFromIndex(entityType: string, entityId: string): Promise<void>;
123
+ bulkIndex(items: Array<{
124
+ entityType: string;
125
+ entityId: string;
126
+ title: string;
127
+ body?: string;
128
+ tags?: string[];
129
+ url: string;
130
+ image?: string;
131
+ metadata?: Record<string, unknown>;
132
+ }>): Promise<{ indexed: number; errors: number }>;
133
+
134
+ removeFromIndex(entityType: string, entityId: string): Promise<boolean>;
84
135
 
136
+ // Search
85
137
  search(query: string, options?: {
86
138
  entityType?: string;
139
+ tags?: string[];
140
+ sort?: SearchSortField;
141
+ fuzzy?: boolean;
87
142
  limit?: number;
88
143
  skip?: number;
89
- }): Promise<{ results: SearchResult[]; total: number }>;
144
+ }): Promise<{
145
+ results: SearchResult[];
146
+ total: number;
147
+ facets: SearchFacets;
148
+ didYouMean?: string;
149
+ }>;
90
150
 
91
151
  suggest(prefix: string, limit?: number): Promise<string[]>;
92
- recordQuery(term: string, resultCount: number, sessionId?: string): Promise<void>;
152
+
153
+ // Analytics
154
+ recordQuery(term: string, resultCount: number, sessionId?: string): Promise<SearchQuery>;
155
+ recordClick(params: {
156
+ queryId: string;
157
+ term: string;
158
+ entityType: string;
159
+ entityId: string;
160
+ position: number;
161
+ }): Promise<SearchClick>;
93
162
  getRecentQueries(sessionId: string, limit?: number): Promise<SearchQuery[]>;
94
163
  getPopularTerms(limit?: number): Promise<PopularTerm[]>;
95
- getZeroResultQueries(limit?: number): Promise<SearchQuery[]>;
164
+ getZeroResultQueries(limit?: number): Promise<PopularTerm[]>;
96
165
  getAnalytics(): Promise<SearchAnalyticsSummary>;
166
+
167
+ // Synonyms
97
168
  addSynonym(term: string, synonyms: string[]): Promise<SearchSynonym>;
98
- removeSynonym(id: string): Promise<void>;
169
+ removeSynonym(id: string): Promise<boolean>;
99
170
  listSynonyms(): Promise<SearchSynonym[]>;
171
+
100
172
  getIndexCount(): Promise<number>;
101
173
  }
102
174
  ```
@@ -104,22 +176,27 @@ interface SearchController {
104
176
  ## Types
105
177
 
106
178
  ```ts
107
- interface SearchIndexItem {
108
- id: string;
109
- entityType: string;
110
- entityId: string;
111
- title: string;
112
- body?: string;
113
- tags: string[];
114
- url?: string;
115
- image?: string;
116
- metadata?: Record<string, unknown>;
117
- indexedAt: Date;
118
- }
179
+ type SearchSortField = "relevance" | "newest" | "oldest" | "title_asc" | "title_desc";
119
180
 
120
181
  interface SearchResult {
121
182
  item: SearchIndexItem;
122
183
  score: number;
184
+ highlights?: { title?: string; body?: string };
185
+ }
186
+
187
+ interface SearchFacets {
188
+ entityTypes: Array<{ type: string; count: number }>;
189
+ tags: Array<{ tag: string; count: number }>;
190
+ }
191
+
192
+ interface SearchClick {
193
+ id: string;
194
+ queryId: string;
195
+ term: string;
196
+ entityType: string;
197
+ entityId: string;
198
+ position: number;
199
+ clickedAt: Date;
123
200
  }
124
201
 
125
202
  interface SearchAnalyticsSummary {
@@ -128,11 +205,76 @@ interface SearchAnalyticsSummary {
128
205
  avgResultCount: number;
129
206
  zeroResultCount: number;
130
207
  zeroResultRate: number;
208
+ clickThroughRate: number;
209
+ avgClickPosition: number;
131
210
  }
211
+ ```
132
212
 
133
- interface PopularTerm {
134
- term: string;
135
- count: number;
136
- avgResultCount: number;
137
- }
213
+ ## Store Components
214
+
215
+ ### SearchBar
216
+
217
+ An autocomplete search input with keyboard navigation support. Fetches suggestions as the user types (minimum 2 characters) and triggers a search callback on submission. Includes a search icon and an accessible combobox dropdown.
218
+
219
+ #### Props
220
+
221
+ | Prop | Type | Required | Description |
222
+ |------|------|----------|-------------|
223
+ | `placeholder` | `string` | No | Placeholder text for the search input. Defaults to `"Search..."`. |
224
+ | `onSearch` | `(query: string) => void` | No | Callback fired when the user submits a search query (via Enter key or suggestion click). |
225
+
226
+ #### Usage in MDX
227
+
228
+ ```mdx
229
+ <SearchBar placeholder="Search products..." onSearch={handleSearch} />
138
230
  ```
231
+
232
+ Best used in the site header or on a search page to provide instant search suggestions as customers type.
233
+
234
+ ### SearchPage
235
+
236
+ A complete search experience combining SearchBar and SearchResults into a single page layout with a heading, search input, and results area. Manages the search query state internally.
237
+
238
+ #### Props
239
+
240
+ | Prop | Type | Required | Description |
241
+ |------|------|----------|-------------|
242
+ | `sessionId` | `string` | No | Optional session ID passed to SearchResults for analytics tracking. |
243
+
244
+ #### Usage in MDX
245
+
246
+ ```mdx
247
+ <SearchPage />
248
+ ```
249
+
250
+ Best used as the main content of a dedicated `/search` page in the storefront.
251
+
252
+ ### SearchResults
253
+
254
+ Displays search results for a given query, with loading and empty states. Fetches results from the search module and renders them as linked cards with optional images.
255
+
256
+ #### Props
257
+
258
+ | Prop | Type | Required | Description |
259
+ |------|------|----------|-------------|
260
+ | `query` | `string` | Yes | The search query string to execute. |
261
+ | `entityType` | `string` | No | Filter results to a specific entity type (e.g., `"product"`). |
262
+ | `sessionId` | `string` | No | Optional session ID for search analytics tracking. |
263
+ | `limit` | `number` | No | Maximum number of results to return. Defaults to `20`. |
264
+
265
+ #### Usage in MDX
266
+
267
+ ```mdx
268
+ <SearchResults query="shoes" entityType="product" limit={10} />
269
+ ```
270
+
271
+ Best used below a search bar to display results, or on a category page for filtered search results.
272
+
273
+ ## Notes
274
+
275
+ - **Fuzzy search** uses Levenshtein distance. Edit tolerance scales with word length: 0 for ≤3 chars, 1 for 4-5 chars, 2 for 6+ chars. Enabled by default.
276
+ - **Facets** are computed from all matching results before pagination, giving accurate counts regardless of page.
277
+ - **Did-you-mean** only activates when zero results are found, checking against indexed titles and historically successful search terms.
278
+ - **Click tracking** records which result was clicked and at what position, enabling CTR and rank quality analytics.
279
+ - **Synonyms** are bidirectional: adding "tee" → ["t-shirt"] means searching for either term finds both.
280
+ - **Highlights** wrap matched terms in `<mark>` tags for rendering in search result UIs.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=controllers.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controllers.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/controllers.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=embedding-provider.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding-provider.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/embedding-provider.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=endpoint-security.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint-security.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/endpoint-security.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=meilisearch-provider.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meilisearch-provider.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/meilisearch-provider.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=service-impl.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-impl.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/service-impl.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export { SearchAnalytics } from "./search-analytics";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/admin/components/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function SearchAnalytics(): import("react").JSX.Element;
2
+ //# sourceMappingURL=search-analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-analytics.d.ts","sourceRoot":"","sources":["../../../src/admin/components/search-analytics.tsx"],"names":[],"mappings":"AA4FA,wBAAgB,eAAe,gCA+T9B"}
@@ -0,0 +1,15 @@
1
+ export declare const analyticsEndpoint: import("better-call").StrictEndpoint<"/admin/search/analytics", {
2
+ method: "GET";
3
+ }, {
4
+ analytics: {
5
+ indexedItems: number;
6
+ totalQueries: number;
7
+ uniqueTerms: number;
8
+ avgResultCount: number;
9
+ zeroResultCount: number;
10
+ zeroResultRate: number;
11
+ clickThroughRate: number;
12
+ avgClickPosition: number;
13
+ };
14
+ }>;
15
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../../src/admin/endpoints/analytics.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;EAW7B,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { z } from "@86d-app/core";
2
+ export declare const bulkIndex: import("better-call").StrictEndpoint<"/admin/search/index/bulk", {
3
+ method: "POST";
4
+ body: z.ZodObject<{
5
+ items: z.ZodArray<z.ZodObject<{
6
+ entityType: z.ZodString;
7
+ entityId: z.ZodString;
8
+ title: z.ZodString;
9
+ body: z.ZodOptional<z.ZodString>;
10
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
11
+ url: z.ZodString;
12
+ image: z.ZodOptional<z.ZodString>;
13
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
14
+ }, z.core.$strip>>;
15
+ }, z.core.$strip>;
16
+ }, {
17
+ indexed: number;
18
+ errors: number;
19
+ }>;
20
+ //# sourceMappingURL=bulk-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-index.d.ts","sourceRoot":"","sources":["../../../src/admin/endpoints/bulk-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,CAAC,EAAE,MAAM,eAAe,CAAC;AAGvD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;EA8BrB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare const clickAnalyticsEndpoint: import("better-call").StrictEndpoint<"/admin/search/clicks", {
2
+ method: "GET";
3
+ }, {
4
+ clickThroughRate: number;
5
+ avgClickPosition: number;
6
+ }>;
7
+ //# sourceMappingURL=click-analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"click-analytics.d.ts","sourceRoot":"","sources":["../../../src/admin/endpoints/click-analytics.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,sBAAsB;;;;;EAYlC,CAAC"}
@@ -0,0 +1,17 @@
1
+ export declare const getSettings: import("better-call").StrictEndpoint<"/admin/search/settings", {
2
+ method: "GET";
3
+ }, {
4
+ meilisearch: {
5
+ configured: boolean;
6
+ host: string | null;
7
+ apiKey: string | null;
8
+ indexUid: string;
9
+ };
10
+ embeddings: {
11
+ configured: boolean;
12
+ provider: string | null;
13
+ model: string;
14
+ };
15
+ indexCount: number;
16
+ }>;
17
+ //# sourceMappingURL=get-settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-settings.d.ts","sourceRoot":"","sources":["../../../src/admin/endpoints/get-settings.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;EAsCvB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { z } from "@86d-app/core";
2
+ export declare const indexItem: import("better-call").StrictEndpoint<"/admin/search/index", {
3
+ method: "POST";
4
+ body: z.ZodObject<{
5
+ entityType: z.ZodString;
6
+ entityId: z.ZodString;
7
+ title: z.ZodString;
8
+ body: z.ZodOptional<z.ZodString>;
9
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
10
+ url: z.ZodString;
11
+ image: z.ZodOptional<z.ZodString>;
12
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
13
+ }, z.core.$strip>;
14
+ }, {
15
+ item: import("../..").SearchIndexItem;
16
+ }>;
17
+ export declare const removeFromIndex: import("better-call").StrictEndpoint<"/admin/search/index/remove", {
18
+ method: "POST";
19
+ body: z.ZodObject<{
20
+ entityType: z.ZodString;
21
+ entityId: z.ZodString;
22
+ }, z.core.$strip>;
23
+ }, {
24
+ removed: boolean;
25
+ }>;
26
+ //# sourceMappingURL=index-manage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-manage.d.ts","sourceRoot":"","sources":["../../../src/admin/endpoints/index-manage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,CAAC,EAAE,MAAM,eAAe,CAAC;AAGvD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;EAuBrB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;EAiB3B,CAAC"}
@@ -0,0 +1,125 @@
1
+ export declare const adminEndpoints: {
2
+ "/admin/search/settings": import("better-call").StrictEndpoint<"/admin/search/settings", {
3
+ method: "GET";
4
+ }, {
5
+ meilisearch: {
6
+ configured: boolean;
7
+ host: string | null;
8
+ apiKey: string | null;
9
+ indexUid: string;
10
+ };
11
+ embeddings: {
12
+ configured: boolean;
13
+ provider: string | null;
14
+ model: string;
15
+ };
16
+ indexCount: number;
17
+ }>;
18
+ "/admin/search/analytics": import("better-call").StrictEndpoint<"/admin/search/analytics", {
19
+ method: "GET";
20
+ }, {
21
+ analytics: {
22
+ indexedItems: number;
23
+ totalQueries: number;
24
+ uniqueTerms: number;
25
+ avgResultCount: number;
26
+ zeroResultCount: number;
27
+ zeroResultRate: number;
28
+ clickThroughRate: number;
29
+ avgClickPosition: number;
30
+ };
31
+ }>;
32
+ "/admin/search/popular": import("better-call").StrictEndpoint<"/admin/search/popular", {
33
+ method: "GET";
34
+ query: import("zod").ZodObject<{
35
+ limit: import("zod").ZodOptional<import("zod").ZodCoercedNumber<unknown>>;
36
+ }, import("zod/v4/core").$strip>;
37
+ }, {
38
+ terms: import("../../service").PopularTerm[];
39
+ }>;
40
+ "/admin/search/zero-results": import("better-call").StrictEndpoint<"/admin/search/zero-results", {
41
+ method: "GET";
42
+ query: import("zod").ZodObject<{
43
+ limit: import("zod").ZodOptional<import("zod").ZodCoercedNumber<unknown>>;
44
+ }, import("zod/v4/core").$strip>;
45
+ }, {
46
+ terms: import("../../service").PopularTerm[];
47
+ }>;
48
+ "/admin/search/clicks": import("better-call").StrictEndpoint<"/admin/search/clicks", {
49
+ method: "GET";
50
+ }, {
51
+ clickThroughRate: number;
52
+ avgClickPosition: number;
53
+ }>;
54
+ "/admin/search/synonyms": import("better-call").StrictEndpoint<"/admin/search/synonyms", {
55
+ method: "GET";
56
+ }, {
57
+ synonyms: import("../..").SearchSynonym[];
58
+ }>;
59
+ "/admin/search/synonyms/add": import("better-call").StrictEndpoint<"/admin/search/synonyms/add", {
60
+ method: "POST";
61
+ body: import("zod").ZodObject<{
62
+ term: import("zod").ZodString;
63
+ synonyms: import("zod").ZodArray<import("zod").ZodString>;
64
+ }, import("zod/v4/core").$strip>;
65
+ }, {
66
+ synonym: import("../..").SearchSynonym;
67
+ }>;
68
+ "/admin/search/synonyms/:id/delete": import("better-call").StrictEndpoint<"/admin/search/synonyms/:id/delete", {
69
+ method: "POST";
70
+ params: import("zod").ZodObject<{
71
+ id: import("zod").ZodString;
72
+ }, import("zod/v4/core").$strip>;
73
+ }, {
74
+ error: string;
75
+ status: number;
76
+ success?: never;
77
+ } | {
78
+ success: boolean;
79
+ error?: never;
80
+ status?: never;
81
+ }>;
82
+ "/admin/search/index": import("better-call").StrictEndpoint<"/admin/search/index", {
83
+ method: "POST";
84
+ body: import("zod").ZodObject<{
85
+ entityType: import("zod").ZodString;
86
+ entityId: import("zod").ZodString;
87
+ title: import("zod").ZodString;
88
+ body: import("zod").ZodOptional<import("zod").ZodString>;
89
+ tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
90
+ url: import("zod").ZodString;
91
+ image: import("zod").ZodOptional<import("zod").ZodString>;
92
+ metadata: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnknown>>;
93
+ }, import("zod/v4/core").$strip>;
94
+ }, {
95
+ item: import("../..").SearchIndexItem;
96
+ }>;
97
+ "/admin/search/index/remove": import("better-call").StrictEndpoint<"/admin/search/index/remove", {
98
+ method: "POST";
99
+ body: import("zod").ZodObject<{
100
+ entityType: import("zod").ZodString;
101
+ entityId: import("zod").ZodString;
102
+ }, import("zod/v4/core").$strip>;
103
+ }, {
104
+ removed: boolean;
105
+ }>;
106
+ "/admin/search/index/bulk": import("better-call").StrictEndpoint<"/admin/search/index/bulk", {
107
+ method: "POST";
108
+ body: import("zod").ZodObject<{
109
+ items: import("zod").ZodArray<import("zod").ZodObject<{
110
+ entityType: import("zod").ZodString;
111
+ entityId: import("zod").ZodString;
112
+ title: import("zod").ZodString;
113
+ body: import("zod").ZodOptional<import("zod").ZodString>;
114
+ tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
115
+ url: import("zod").ZodString;
116
+ image: import("zod").ZodOptional<import("zod").ZodString>;
117
+ metadata: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnknown>>;
118
+ }, import("zod/v4/core").$strip>>;
119
+ }, import("zod/v4/core").$strip>;
120
+ }, {
121
+ indexed: number;
122
+ errors: number;
123
+ }>;
124
+ };
125
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/admin/endpoints/index.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAY1B,CAAC"}