@van1s1mys/ai-router 1.0.0
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.cjs +215 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +172 -0
- package/dist/index.d.ts +172 -0
- package/dist/index.js +188 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for a single route entry.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* const route: RouteConfig = {
|
|
7
|
+
* path: '/pricing',
|
|
8
|
+
* title: 'Pricing',
|
|
9
|
+
* description: 'Plans, pricing, billing, subscription',
|
|
10
|
+
* };
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
interface RouteConfig {
|
|
14
|
+
/** URL path of the route (e.g. `"/pricing"`, `"/about/team"`). */
|
|
15
|
+
path: string;
|
|
16
|
+
/** Human-readable title used for semantic matching. */
|
|
17
|
+
title: string;
|
|
18
|
+
/**
|
|
19
|
+
* Optional description with keywords/synonyms to improve search accuracy.
|
|
20
|
+
* The more context you provide, the better the matching quality.
|
|
21
|
+
*/
|
|
22
|
+
description?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Options for creating a {@link SmartRouter} instance.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const options: RouteOptions = {
|
|
30
|
+
* routes: [
|
|
31
|
+
* { path: '/pricing', title: 'Pricing', description: 'cost, plans' },
|
|
32
|
+
* { path: '/contact', title: 'Contact', description: 'support, phone' },
|
|
33
|
+
* ],
|
|
34
|
+
* model: 'Xenova/all-MiniLM-L6-v2',
|
|
35
|
+
* threshold: 0.5,
|
|
36
|
+
* };
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
interface RouteOptions {
|
|
40
|
+
/** Array of routes to index for semantic search. */
|
|
41
|
+
routes: RouteConfig[];
|
|
42
|
+
/**
|
|
43
|
+
* HuggingFace model ID for generating embeddings.
|
|
44
|
+
* Must produce 384-dimensional vectors.
|
|
45
|
+
* @default "Xenova/all-MiniLM-L6-v2"
|
|
46
|
+
*/
|
|
47
|
+
model?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Minimum similarity score (0–1) for a result to be returned.
|
|
50
|
+
* Results below this threshold are discarded.
|
|
51
|
+
* @default 0.5
|
|
52
|
+
*/
|
|
53
|
+
threshold?: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Result returned by {@link SmartRouter.search}.
|
|
57
|
+
* Contains the best matching route path and its similarity score.
|
|
58
|
+
*/
|
|
59
|
+
interface SearchResult {
|
|
60
|
+
/** URL path of the matched route. */
|
|
61
|
+
path: string;
|
|
62
|
+
/** Similarity score between 0 and 1 (higher = better match). */
|
|
63
|
+
score: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* AI-powered semantic search router.
|
|
68
|
+
*
|
|
69
|
+
* Runs a HuggingFace embedding model inside a Web Worker and uses
|
|
70
|
+
* Orama's hybrid (text + vector) search to find the best matching
|
|
71
|
+
* route for a natural-language query.
|
|
72
|
+
*
|
|
73
|
+
* **SSR-safe**: on the server (Node.js), the instance is created
|
|
74
|
+
* without a worker. `ready` resolves immediately and `search()`
|
|
75
|
+
* always returns `null`. The worker is only spawned in the browser.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { SmartRouter } from 'ai-router';
|
|
80
|
+
*
|
|
81
|
+
* const router = new SmartRouter({
|
|
82
|
+
* routes: [
|
|
83
|
+
* { path: '/pricing', title: 'Pricing', description: 'cost, plans, subscription' },
|
|
84
|
+
* { path: '/contact', title: 'Contact', description: 'support, phone, address' },
|
|
85
|
+
* ],
|
|
86
|
+
* threshold: 0.5,
|
|
87
|
+
* });
|
|
88
|
+
*
|
|
89
|
+
* // Wait for the model to load (~22 MB on first run, cached afterwards)
|
|
90
|
+
* await router.ready;
|
|
91
|
+
*
|
|
92
|
+
* // Search by meaning — typos and synonyms work too
|
|
93
|
+
* const result = await router.search('how much does it cost?');
|
|
94
|
+
* // → { path: '/pricing', score: 0.87 }
|
|
95
|
+
*
|
|
96
|
+
* // Cleanup when done
|
|
97
|
+
* router.destroy();
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
declare class SmartRouter {
|
|
101
|
+
private worker;
|
|
102
|
+
private readyPromise;
|
|
103
|
+
private resolveReady;
|
|
104
|
+
private rejectReady;
|
|
105
|
+
private pendingSearches;
|
|
106
|
+
private destroyed;
|
|
107
|
+
private readonly ssr;
|
|
108
|
+
/**
|
|
109
|
+
* Creates a new SmartRouter instance.
|
|
110
|
+
*
|
|
111
|
+
* Spawns a Web Worker, downloads the embedding model, and indexes
|
|
112
|
+
* all provided routes. The instance is usable after {@link ready} resolves.
|
|
113
|
+
*
|
|
114
|
+
* In a server environment (no `Worker` API), the instance is inert:
|
|
115
|
+
* `ready` resolves immediately and `search()` returns `null`.
|
|
116
|
+
*
|
|
117
|
+
* @param options - Routes to index, model ID, and similarity threshold.
|
|
118
|
+
*/
|
|
119
|
+
constructor(options: RouteOptions);
|
|
120
|
+
/**
|
|
121
|
+
* Promise that resolves when the model is loaded and routes are indexed.
|
|
122
|
+
* Rejects if initialization fails (e.g. network error, invalid model).
|
|
123
|
+
* Resolves immediately on the server.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* await router.ready;
|
|
128
|
+
* console.log('Model loaded, ready to search');
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
get ready(): Promise<void>;
|
|
132
|
+
/** @internal Initializes the worker and sends the INIT message. */
|
|
133
|
+
private initWorker;
|
|
134
|
+
/**
|
|
135
|
+
* Finds the best matching route for a natural-language query.
|
|
136
|
+
*
|
|
137
|
+
* Waits for {@link ready} automatically, so it's safe to call
|
|
138
|
+
* right after construction — the first search will just take longer.
|
|
139
|
+
*
|
|
140
|
+
* Returns `null` during SSR (server-side rendering).
|
|
141
|
+
*
|
|
142
|
+
* @param query - Free-text search query (e.g. "how to contact support").
|
|
143
|
+
* @returns The best matching route, or `null` if no route meets the threshold.
|
|
144
|
+
* @throws If the router has been {@link destroy destroyed} or the worker crashes.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const result = await router.search('where are your offices?');
|
|
149
|
+
* if (result) {
|
|
150
|
+
* window.location.href = result.path; // "/contact"
|
|
151
|
+
* }
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
search(query: string): Promise<SearchResult | null>;
|
|
155
|
+
/**
|
|
156
|
+
* Terminates the worker and rejects all pending searches.
|
|
157
|
+
*
|
|
158
|
+
* After calling `destroy()`, the instance is no longer usable.
|
|
159
|
+
* Calling `destroy()` multiple times is safe (no-op after the first call).
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* // In a SPA, destroy when navigating away
|
|
164
|
+
* onUnmount(() => router.destroy());
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
destroy(): void;
|
|
168
|
+
/** @internal Rejects all pending search promises with the given error. */
|
|
169
|
+
private rejectAllPending;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export { type RouteConfig, type RouteOptions, type SearchResult, SmartRouter };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for a single route entry.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* const route: RouteConfig = {
|
|
7
|
+
* path: '/pricing',
|
|
8
|
+
* title: 'Pricing',
|
|
9
|
+
* description: 'Plans, pricing, billing, subscription',
|
|
10
|
+
* };
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
interface RouteConfig {
|
|
14
|
+
/** URL path of the route (e.g. `"/pricing"`, `"/about/team"`). */
|
|
15
|
+
path: string;
|
|
16
|
+
/** Human-readable title used for semantic matching. */
|
|
17
|
+
title: string;
|
|
18
|
+
/**
|
|
19
|
+
* Optional description with keywords/synonyms to improve search accuracy.
|
|
20
|
+
* The more context you provide, the better the matching quality.
|
|
21
|
+
*/
|
|
22
|
+
description?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Options for creating a {@link SmartRouter} instance.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const options: RouteOptions = {
|
|
30
|
+
* routes: [
|
|
31
|
+
* { path: '/pricing', title: 'Pricing', description: 'cost, plans' },
|
|
32
|
+
* { path: '/contact', title: 'Contact', description: 'support, phone' },
|
|
33
|
+
* ],
|
|
34
|
+
* model: 'Xenova/all-MiniLM-L6-v2',
|
|
35
|
+
* threshold: 0.5,
|
|
36
|
+
* };
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
interface RouteOptions {
|
|
40
|
+
/** Array of routes to index for semantic search. */
|
|
41
|
+
routes: RouteConfig[];
|
|
42
|
+
/**
|
|
43
|
+
* HuggingFace model ID for generating embeddings.
|
|
44
|
+
* Must produce 384-dimensional vectors.
|
|
45
|
+
* @default "Xenova/all-MiniLM-L6-v2"
|
|
46
|
+
*/
|
|
47
|
+
model?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Minimum similarity score (0–1) for a result to be returned.
|
|
50
|
+
* Results below this threshold are discarded.
|
|
51
|
+
* @default 0.5
|
|
52
|
+
*/
|
|
53
|
+
threshold?: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Result returned by {@link SmartRouter.search}.
|
|
57
|
+
* Contains the best matching route path and its similarity score.
|
|
58
|
+
*/
|
|
59
|
+
interface SearchResult {
|
|
60
|
+
/** URL path of the matched route. */
|
|
61
|
+
path: string;
|
|
62
|
+
/** Similarity score between 0 and 1 (higher = better match). */
|
|
63
|
+
score: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* AI-powered semantic search router.
|
|
68
|
+
*
|
|
69
|
+
* Runs a HuggingFace embedding model inside a Web Worker and uses
|
|
70
|
+
* Orama's hybrid (text + vector) search to find the best matching
|
|
71
|
+
* route for a natural-language query.
|
|
72
|
+
*
|
|
73
|
+
* **SSR-safe**: on the server (Node.js), the instance is created
|
|
74
|
+
* without a worker. `ready` resolves immediately and `search()`
|
|
75
|
+
* always returns `null`. The worker is only spawned in the browser.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { SmartRouter } from 'ai-router';
|
|
80
|
+
*
|
|
81
|
+
* const router = new SmartRouter({
|
|
82
|
+
* routes: [
|
|
83
|
+
* { path: '/pricing', title: 'Pricing', description: 'cost, plans, subscription' },
|
|
84
|
+
* { path: '/contact', title: 'Contact', description: 'support, phone, address' },
|
|
85
|
+
* ],
|
|
86
|
+
* threshold: 0.5,
|
|
87
|
+
* });
|
|
88
|
+
*
|
|
89
|
+
* // Wait for the model to load (~22 MB on first run, cached afterwards)
|
|
90
|
+
* await router.ready;
|
|
91
|
+
*
|
|
92
|
+
* // Search by meaning — typos and synonyms work too
|
|
93
|
+
* const result = await router.search('how much does it cost?');
|
|
94
|
+
* // → { path: '/pricing', score: 0.87 }
|
|
95
|
+
*
|
|
96
|
+
* // Cleanup when done
|
|
97
|
+
* router.destroy();
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
declare class SmartRouter {
|
|
101
|
+
private worker;
|
|
102
|
+
private readyPromise;
|
|
103
|
+
private resolveReady;
|
|
104
|
+
private rejectReady;
|
|
105
|
+
private pendingSearches;
|
|
106
|
+
private destroyed;
|
|
107
|
+
private readonly ssr;
|
|
108
|
+
/**
|
|
109
|
+
* Creates a new SmartRouter instance.
|
|
110
|
+
*
|
|
111
|
+
* Spawns a Web Worker, downloads the embedding model, and indexes
|
|
112
|
+
* all provided routes. The instance is usable after {@link ready} resolves.
|
|
113
|
+
*
|
|
114
|
+
* In a server environment (no `Worker` API), the instance is inert:
|
|
115
|
+
* `ready` resolves immediately and `search()` returns `null`.
|
|
116
|
+
*
|
|
117
|
+
* @param options - Routes to index, model ID, and similarity threshold.
|
|
118
|
+
*/
|
|
119
|
+
constructor(options: RouteOptions);
|
|
120
|
+
/**
|
|
121
|
+
* Promise that resolves when the model is loaded and routes are indexed.
|
|
122
|
+
* Rejects if initialization fails (e.g. network error, invalid model).
|
|
123
|
+
* Resolves immediately on the server.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* await router.ready;
|
|
128
|
+
* console.log('Model loaded, ready to search');
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
get ready(): Promise<void>;
|
|
132
|
+
/** @internal Initializes the worker and sends the INIT message. */
|
|
133
|
+
private initWorker;
|
|
134
|
+
/**
|
|
135
|
+
* Finds the best matching route for a natural-language query.
|
|
136
|
+
*
|
|
137
|
+
* Waits for {@link ready} automatically, so it's safe to call
|
|
138
|
+
* right after construction — the first search will just take longer.
|
|
139
|
+
*
|
|
140
|
+
* Returns `null` during SSR (server-side rendering).
|
|
141
|
+
*
|
|
142
|
+
* @param query - Free-text search query (e.g. "how to contact support").
|
|
143
|
+
* @returns The best matching route, or `null` if no route meets the threshold.
|
|
144
|
+
* @throws If the router has been {@link destroy destroyed} or the worker crashes.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const result = await router.search('where are your offices?');
|
|
149
|
+
* if (result) {
|
|
150
|
+
* window.location.href = result.path; // "/contact"
|
|
151
|
+
* }
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
search(query: string): Promise<SearchResult | null>;
|
|
155
|
+
/**
|
|
156
|
+
* Terminates the worker and rejects all pending searches.
|
|
157
|
+
*
|
|
158
|
+
* After calling `destroy()`, the instance is no longer usable.
|
|
159
|
+
* Calling `destroy()` multiple times is safe (no-op after the first call).
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* // In a SPA, destroy when navigating away
|
|
164
|
+
* onUnmount(() => router.destroy());
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
destroy(): void;
|
|
168
|
+
/** @internal Rejects all pending search promises with the given error. */
|
|
169
|
+
private rejectAllPending;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export { type RouteConfig, type RouteOptions, type SearchResult, SmartRouter };
|